AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi [Andorra] Kollisionserkennung verbessern
Thema durchsuchen
Ansicht
Themen-Optionen

[Andorra] Kollisionserkennung verbessern

Offene Frage von "Diamondback2007"
Ein Thema von Diamondback2007 · begonnen am 17. Jul 2008 · letzter Beitrag vom 21. Jul 2008
Antwort Antwort
Benutzerbild von Diamondback2007
Diamondback2007

Registriert seit: 2. Feb 2007
260 Beiträge
 
Delphi 2007 Professional
 
#1

[Andorra] Kollisionserkennung verbessern

  Alt 17. Jul 2008, 13:02
Hallo zusammen,

ich habe im Moment folgenden Code um auf Kollisionen mit meinen Bricks bei meinem Breakoutspiel zu reagieren.
Delphi-Quellcode:
procedure TBall.DoBrickCollision(aBrick: TSprite);
var
  ObenUnten : Boolean;
  linksRechts : Boolean;
const
  Puffer = 0.6;
begin
  (aBrick as Tbrick).Hit;
  if Settings.DoBrickCollisions then
    begin
      ObenUnten := false;
      LinksRechts := false;
      if BoundsRect.Top + (GameForm.AdPerCounter.TimeGap * Puffer) >= aBrick.BoundsRect.Bottom then
        begin
          ObenUnten := true;
          Y := aBrick.BoundsRect.Bottom;
        end;
      if BoundsRect.Bottom - (GameForm.AdPerCounter.TimeGap * Puffer) <= aBrick.BoundsRect.Top then
        begin
          ObenUnten := true;
          Y := aBrick.Y - Height;
        end;
      if BoundsRect.Right - (GameForm.AdPerCounter.TimeGap * Puffer) <= aBrick.BoundsRect.Left then
        begin
          LinksRechts := true;
          X := aBrick.X - Width;
        end;
      if BoundsRect.Left + (GameForm.AdPerCounter.TimeGap * Puffer) >= aBrick.BoundsRect.Right then
        begin
          LinksRechts := true;
          X := aBrick.BoundsRect.Right;
        end;

      if ObenUnten then
        ChangeYDir
      else if LinksRechts then
        ChangeXDir;
    end;
end;
Das klappt eigentlich auch schon recht gut, allerdings nicht immer...
Z.B. bei eingeschaltetem VertSync nicht mehr wirklich gut, da die Framerate dann bei 60 statt 1700 liegt. Für diesen Fall hatte ich eigentlich schon den Puffer da eingebaut, der je nach FPS noch ein paar Pixel mehr oder weniger rechnet...
Aber manchmal fliegt der Ball trotzdem durch die Steine durch...

Hat jemand eine besser Idee? Das wäre super
Fabian E.
  Mit Zitat antworten Zitat
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#2

Re: [Andorra] Kollisionserkennung verbessern

  Alt 17. Jul 2008, 14:11
Gehe die Sprite-Liste per Hand durch und berechne eine Kollision über das Separating Axis Theorem:
http://www.delphipraxis.net/posting....ets=1216296554

Du kannst über alle Sprites in der Spriteengine über Engine.Items iterieren.

Edit: Andere Möglichkeit: Führe die Bewegungen und Kollisionskontrollen in einem anderen Thread als das Zeichnen aus. Denke jedoch daran, alle Spriteenginezugriffe über eine Criticalsection zu schützen.
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Benutzerbild von Diamondback2007
Diamondback2007

Registriert seit: 2. Feb 2007
260 Beiträge
 
Delphi 2007 Professional
 
#3

Re: [Andorra] Kollisionserkennung verbessern

  Alt 17. Jul 2008, 15:01
Okay, kannst du vielleicht dann noch dne richtigen Links posten?
Fabian E.
  Mit Zitat antworten Zitat
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#4

Re: [Andorra] Kollisionserkennung verbessern

  Alt 17. Jul 2008, 15:49

http://wiki.delphigl.com/index.php/T...g_Axis_Theorem
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Benutzerbild von Diamondback2007
Diamondback2007

Registriert seit: 2. Feb 2007
260 Beiträge
 
Delphi 2007 Professional
 
#5

Re: [Andorra] Kollisionserkennung verbessern

  Alt 17. Jul 2008, 17:04
Zitat:
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200). Die Koordinaten der Vertices werden absolut zur Position und entgegen des Uhrzeigersinns angegeben
Argh... Mir raucht der Kopf Was genu heißt das jetzt? Also das mit dem absolut zur Position..
Einfach die jeweiligen Ecken mit ihrer Position angeben?
Fabian E.
  Mit Zitat antworten Zitat
Benutzerbild von Diamondback2007
Diamondback2007

Registriert seit: 2. Feb 2007
260 Beiträge
 
Delphi 2007 Professional
 
#6

Re: [Andorra] Kollisionserkennung verbessern

  Alt 17. Jul 2008, 20:31
Ach das ist doch alles blöd
Ich bekomm das nicht hin mit dem "Seperating Axis Theorem"...
Ich poste mal meinen Code:
Die Polygonklasse:
Delphi-Quellcode:
unit uPolygon;

interface

uses
  AdPhysics,
  Vectors,
  Math;

type
  // Array mit den Vertices des Polygons
  TV2fArray = array of TVector2f;
  // Polygon Klasse
  TPolygon = class(TPhysicalBoxSprite)
  private
    fposition: TVector2f; // Position
    fvertices: TV2fArray; // Vertices (Objektkoordinaten)
    function GetVertex(n: integer): TVector2f; // Liefert die Objektkoordinaten
    function GetVertexAbs(n: integer): TVector2f; // Liefert die absoluten Koordinaten
    procedure SetVertex(n: integer; Value: TVector2f); // Setzt die Objektkoordinaten
    function GetCount: integer; // Liefert length(fvertices)
  public
    procedure AddVertex(v: TVector2f); // Fügt ein Vertex hinzu
    procedure AddVertexAbs(v: TVector2f); // Fügt ein Vertex mit Weltkoordinaten hinzu
    procedure RemoveVertex(n: integer); // Entfernt ein Vertex
    property position: TVector2f read fposition write fposition; // Position
    property vertices[n: integer]: TVector2f read GetVertex write SetVertex; // Vertex Koordinaten
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs; // Vertex Weltkoordinaten
    property Count: integer read GetCount; // siehe GetCount
  end;
  TPolygonArray = array of TPolygon;

function BrickBallIntersect(A, B: TPolygon; var MTD: TVector2f): boolean;

implementation

function CreateAxis(P: TPolygon): TV2fArray;
var
  i, l : integer;
  tmp : TVector2f;
begin
  for i := 0 to (P.count - 1) do
    begin
      l := i + 1;
      if l > (P.count - 1) then
        l := 0;
      // Berechnung der Seitenfläche
      tmp := v2f_sub(P.vertices[l], P.vertices[i]);
      // Berechnet die Normale der Seitenfläche
      setlength(result, length(result) + 1);
      result[high(result)] := v2f_normalize(to_v2f(-tmp.y, tmp.x));
    end;
end;

procedure ProjectOntoAxis(P: TPolygon; proj: TVector2f; var pmin, pmax: extended);
var
  i : integer;
  dp : extended;
begin // Projeziert den ersten Wert
  pmin := v2f_dotproduct(P.vertices[0], proj);
  pmax := pmin;
  // Findet den kleinsten und größten projezierten Wert für die Gerade für P
  for i := 1 to (P.count - 1) do
    begin
      // projezieren
      dp := v2f_dotproduct(P.vertices[i], proj);
      if dp < pmin then
        pmin := dp;
      if dp > pmax then
        pmax := dp;
    end;
end;

function CollisionCheck(A, B: TPolygon; var axis: TVector2f; voffset: TVector2f): boolean;
var
  foffset,
    amin, amax,
    bmin, bmax,
    d1, d2, depth : extended;
begin
  ProjectOntoAxis(A, axis, amin, amax);
  ProjectOntoAxis(B, axis, bmin, bmax);
  foffset := v2f_dotproduct(voffset, axis);
  amin := amin + foffset;
  amax := amax + foffset;
  d1 := amin - bmax;
  d2 := bmin - amax;
  // Wenn es keine Überschneidung gibt, abbrechen -> keine Kollision
  if (d1 > 0) or (d2 > 0) then
    begin
      result := false;
      exit;
    end;
  // Ansonsten den Verschiebungsvektor bestimmen
  depth := max(d1, d2);
  axis := v2f_scale(axis, abs(depth));
  result := true;
end;

function BrickBallIntersect(A, B: TPolygon; var MTD: TVector2f): boolean;
var
  axis : TV2fArray;
  voffset : TVector2f;
  i : integer;
begin
  MTD := to_v2f(0, 0);
  // Offset berechnen
  voffset := v2f_sub(A.position, B.position);
  // Alle Achsen für A
  axis := CreateAxis(A);
  // Alle Achsen für B
  axis := CreateAxis(B);
  // Projezieren der Polygone
  for i := 0 to high(axis) do
    if not CollisionCheck(A, B, axis[i], voffset) then
      begin
        result := false;
        exit;
      end;
  // MTD bestimmen
  MTD := axis[0];
  for i := 1 to high(axis) do
    if v2f_length(axis[i]) < v2f_length(MTD) then
      MTD := axis[i];
  if v2f_dotproduct(voffset, MTD) < 0 then
    MTD := v2f_scale(MTD, -1);
  // Kollision
  result := true;
end;

{ TPolygon }

procedure TPolygon.AddVertex(v: TVector2f);
begin
  setlength(fvertices, length(fvertices) + 1);
  fvertices[high(fvertices)] := v2f_sub(v, position);
end;

procedure TPolygon.AddVertexAbs(v: TVector2f);
begin
  setlength(fvertices, length(fvertices) + 1);
  fvertices[high(fvertices)] := v;
end;

function TPolygon.GetCount: integer;
begin
  result := length(fvertices);
end;

function TPolygon.GetVertex(n: integer): TVector2f;
var
  acos, asin : extended;
begin
  sincos(degtorad(angle), asin, acos);
  result.x := fvertices[n].x * acos + fvertices[n].y * -asin;
  result.y := fvertices[n].x * asin + fvertices[n].y * acos;
end;

function TPolygon.GetVertexAbs(n: integer): TVector2f;
begin
  result := v2f_add(fvertices[n], fposition);
end;

procedure TPolygon.RemoveVertex(n: integer);
var
  i : integer;
begin
  for i := n to high(fvertices) - 1 do
    fvertices[i] := fvertices[i + 1];
  setlength(fvertices, length(fvertices) - 1);
end;

procedure TPolygon.SetVertex(n: integer; Value: TVector2f);
begin
  fvertices[n] := Value;
end;

end.
Die ist nur abkopiert, sollte also soweit richtig sein.

Dann noch die Erstellung meiner Objekte:
Delphi-Quellcode:
procedure TGameForm.AddBrick(aX, aY: Double; aColor: Integer);
begin
  with TBrick.Create(AdSpriteEngine) do
    begin
      Image := AdImgLst.Find('brick');
      X := 1 + aX;
      Y := 1 + aY;
      Width := 90;
      Height := 20;
      Position := to_v2f(X, Y);
      AddVertex(to_v2f(90, -20));
      AddVertex(to_v2f(90, 0));
      AddVertex(to_v2f(0, 0));
      AddVertex(to_v2f(0, -20));
     { AddVertex(to_v2f(BoundsRect.Right, BoundsRect.Bottom));
      AddVertex(to_v2f(BoundsRect.Right, BoundsRect.Top));
      AddVertex(to_v2f(BoundsRect.Left, BoundsRect.Top));
      AddVertex(to_v2f(BoundsRect.Left, BoundsRect.Bottom));}

      Color := aColor;
      Typ := ptStatic;
      InitializeShape;
    end;
end;
und
Delphi-Quellcode:
procedure TGameForm.NewBall;
begin
  with TBall.Create(AdSpriteEngine) do
    begin
      Image := AdImgLst.Find('ball');
      X := Bat.X + Bat.Width / 2;
      Y := Bat.Y;
      Width := 10;
      Height := 10;
      Position := to_v2f(X, Y);
      AddVertex(to_v2f(10, -10));
      AddVertex(to_v2f(10, 0));
      AddVertex(to_v2f(0, 0));
      AddVertex(to_v2f(0, -10));
      {AddVertex(to_v2f(BoundsRect.Right, BoundsRect.Bottom));
      AddVertex(to_v2f(BoundsRect.Right, BoundsRect.Top));
      AddVertex(to_v2f(BoundsRect.Left, BoundsRect.Top));
      AddVertex(to_v2f(BoundsRect.Left, BoundsRect.Bottom));  }

    end;
  Bat.IsBallOnbat := true;
end;
Die Überprüfung findet hier statt:
Delphi-Quellcode:
for i := 0 to GameForm.AdSpriteEngine.Items.Count - 1 do
    begin
      if GameForm.AdSpriteEngine.Items[i] is TBrick then
        begin
          if BrickBallIntersect(GameForm.AdSpriteEngine.Items[i] as TBrick, self, MTD) then
            DoBrickCollision(GameForm.AdSpriteEngine.Items[i]);
        end;
    end;
Wenn ich das ganze starte, dann werden alle Bricks gleichzeitig "berührt" und verschwinden dann. Die Kollisionsabfrage klappt also nicht richtig...
Fabian E.
  Mit Zitat antworten Zitat
Benutzerbild von Diamondback2007
Diamondback2007

Registriert seit: 2. Feb 2007
260 Beiträge
 
Delphi 2007 Professional
 
#7

Re: [Andorra] Kollisionserkennung verbessern

  Alt 21. Jul 2008, 11:30
Ja also ich bekomms einfach nicht hin...
Hat jemand schon mal was funktionieredes damit gemacht?
@igel: Warum baust du das eigentlich nicht in deine Engine ein als Erkennung?Oder hast du das schon?
Fabian E.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:58 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz