Einzelnen Beitrag anzeigen

Sangoku

Registriert seit: 13. Jan 2006
10 Beiträge
 
#1

Kollisionsabfrage für gedrehte Sprites mittels Vektoren

  Alt 28. Feb 2006, 19:44
Hallo alle zusammen.

Ich hab da mal ein Problemchen. Und zwar programmieren wir in der Schule grad ein paar Spielchen, und dabei kam das Problem auf, dass ein Sprite, das über die Angle-Eigenschaft gedreht wird, dafür seinen Pixelcheck einbüßen muss. Da dachte ich mir kein Problem - schreibst de einfach selber.

Zuerst hab ich mittels Bogenmaßrechnungen die X,Y-Koordinate des Sprites imaginär mit dem Winkel im Kreis wandern lassen, da die Orginal X,Y-Koordinate sich bei der Drehung des Sprites nicht verändert.

Delphi-Quellcode:
procedure TFigur.WinkelinVektoren;
var rad : Double;
begin
  //deg in rad umrechnen
  rad := ((Angle / 255 * 360) - 135) * (pi/180);

  //Die Drehung der X, Y Koordinate des Sprites simulieren
  XO := XU + cos(rad) * Radius;
  YO := YU + sin(rad) * Radius;
XU, YU stehen für den Mittelpunkt des Sprites - den Ursprung - und XO, YO sind die Koordinaten der wandernden Ecke oben links, die sich ja theoretisch mit der Drehung des Sprites mitdreht.

Als nächstes hab ich über das Bild im Sprite eine Ebene durch zwei Vektoren beschrieben, in der eine Pixelabfrage stattfindet. Vorerst soll die Kollisionsabfrage nämlich nur den Hintergrund auf Farben überprüfen.

Delphi-Quellcode:
rad := (Angle / 255 * 360) * (pi/180);

  //Richtungsvektor berechnen
  MoveVek.x := -(sin(rad)*yDiff);
  MoveVek.y := cos(rad)*yDiff;

  //Vektor der Höhe der Figur
  HochVek.x := -(sin(rad));
  HochVek.y := cos(rad);

  //Vektor der Breite der Figur
  rad := ((Angle / 255 * 360) - 90) * (pi/180);

  BreitVek.x := -(sin(rad));
  BreitVek.y := cos(rad);
end;
Der MoveVek ist der RichtungsVektor, der für die Bewegung des Sprites nach vorne und hinten zuständig ist. Der HochVek steht für die Höhe des Sprites und der BreitVek für dessen Breite.
Alle drei Vektoren drehen sich mit dem Bild im Sprite.

Soweit so gut, nun kommt die Pixelabfrage

Delphi-Quellcode:
function TFigur.PixelKollision(Farbe : TColor): TKollision;
var
  xi, yi : Integer;
  xw, yw : Double;
  Flag : Boolean;
  Status : TKollision;
begin
  Flag := false;
  Status := None;

  for yi := 0 to Width do begin
    for xi := 0 to Height do begin
      xw := XO + (BreitVek.x * xi) + (HochVek.x * yi);
      yw := YO + (BreitVek.y * xi) + (HochVek.y * yi);
      if Image.Picture.Bitmap.Canvas.Pixels[Round(xw - XO), Round(yw - YO)] <> Image.TransparentColor then
        if Form1.Spielfeld.Image.Picture.Bitmap.Canvas.Pixels[Round(xw), Round(yw)] = Farbe then begin
          Flag := true;
          if yw - YO < 0 then yw := -(yw - YO); //Hiermit will ich ermitteln
          if yw - YO <= Height div 2 then //ob die Kollsion beim vorwärts oder
            Status := Vorne //rückwärts laufen stattfindet
          else
            Status := Hinten;
          Break;
        end;
    end;
    if Flag then Break;
  end;

  Result := Status;
end;
Sie überprüft den Hintergrund auf eine variable Farbe, die mit Funktionsaufruf übergeben wird, aber nur in dem Bereich des Sprites, der auch tatsächlich von der Spielfigur überdeckt wird. Der Bereich, der als transparent deklariert ist, soll nicht überprüft werden.

Ich habe das gleich Verfahren in einem Testprogramm angewendet, hab dort allerdings statt nicht Pixel abgefragt, sonderm gezeichnet. Die Drehung und die Vektorebene funktionieren eigentlich einwandrei.

Delphi-Quellcode:
type
  TVektor = class
  private

  public
    x, y : Double;
    constructor Create;
    destructor Free;
  end;

type
  TForm1 = class(TForm)
    Image1: TImage;
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
    procedure WinkelinVektoren;
    procedure PixelKollision;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  MoveVek, HochVek, BreitVek : TVektor;
  Angle, X, Y : Integer;
  XO, YO, XU, YU, Radius : Double;

implementation

{$R *.dfm}

constructor TVektor.Create; begin end;

destructor TVektor.Free; begin end;

procedure TForm1.WinkelinVektoren;
var rad : Double;
begin
  //deg in rad umrechnen
  rad := ((Angle / 255 * 360) - 135) * (pi/180);

  //neue Koordinaten setzten
  XO := 100 + cos(rad) * Radius;
  YO := 100 + sin(rad) * Radius;

  Image1.Canvas.Pixels[50, 50] := clBlack;
  Image1.Canvas.Pixels[Round(XO), Round(YO)] := clBlack;

  rad := (Angle / 255 * 360) * (pi/180);

  //Richtungsvektor berechnen
  MoveVek.x := -(sin(rad)*30);
  MoveVek.y := cos(rad)*20;

  //Vektor der Höhe der Figur
  HochVek.x := -(sin(rad));
  HochVek.y := cos(rad);

  //Vektor der Breite der Figur
  rad := ((Angle / 255 * 360) - 90) * (pi/180);

  BreitVek.x := -(sin(rad));
  BreitVek.y := cos(rad);
end;

procedure TForm1.PixelKollision;
var
  xi, yi : Integer;
  xw, yw : Double;
begin
  for yi := 0 to 45 do begin
    for xi := 0 to 45 do begin
      xw := XO + (BreitVek.x * xi) + (HochVek.x * yi);
      yw := YO + (BreitVek.y * xi) + (HochVek.y * yi);
      Image1.Canvas.Pixels[Round(xw), Round(yw)] := clBlack;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MoveVek := TVektor.Create;
  BreitVek := TVektor.Create;
  HochVek := TVektor.Create;

  Radius := sqrt((45*45)*2);
  Radius := Radius / 2;

  X := Image1.Width div 2;
  Y := Image1.Height div 2;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_Left then Angle := Angle - 2;
  if Key = VK_Right then Angle := Angle + 2;
  WinkelinVektoren;
  //Image1.Canvas.Rectangle(0, 0, Image1.Width, Image1.Height);
  PixelKollision;
end;

end.
Aber dennoch funktioniert die Kollisionsabfrage nicht richtig. Sobald ich das Objekt drehe und rumlaufe, passieren absolut verrückte Sachen. Mal wird die Farbe ignoriert oder gar dort erkannt, wo sie gar nicht ist. Wäre dür Hilfe echt dankbar, denn ich bin mit meinem Latein doch schon bald so ziemlich am Ende. Ich häng das komplette Programm mal als Anhang hinten dran.

Danke schon mal im voraus
Angehängte Dateien
Dateityp: rar atschool_868.rar (2,19 MB, 10x aufgerufen)
  Mit Zitat antworten Zitat