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