[Andorra] Kollisionserkennung verbessern
Hallo zusammen,
ich habe im Moment folgenden Code um auf Kollisionen mit meinen Bricks bei meinem Breakoutspiel zu reagieren.
Delphi-Quellcode:
Das klappt eigentlich auch schon recht gut, allerdings nicht immer...
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; 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 :) |
Re: [Andorra] Kollisionserkennung verbessern
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. |
Re: [Andorra] Kollisionserkennung verbessern
Okay, kannst du vielleicht dann noch dne richtigen Links posten? ;)
|
Re: [Andorra] Kollisionserkennung verbessern
|
Re: [Andorra] Kollisionserkennung verbessern
Zitat:
Einfach die jeweiligen Ecken mit ihrer Position angeben? |
Re: [Andorra] Kollisionserkennung verbessern
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:
Die ist nur abkopiert, sollte also soweit richtig sein.
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. Dann noch die Erstellung meiner Objekte:
Delphi-Quellcode:
und
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;
Delphi-Quellcode:
Die Überprüfung findet hier statt:
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;
Delphi-Quellcode:
Wenn ich das ganze starte, dann werden alle Bricks gleichzeitig "berührt" und verschwinden dann. Die Kollisionsabfrage klappt also nicht richtig...
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; |
Re: [Andorra] Kollisionserkennung verbessern
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? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:51 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