![]() |
Vektordistanz Fadenkreuz zu Spieler (2D) berechnen
Hallo,
ich stehe vor einem mehr oder weniger mathematischen Problem. Ich versuche die Distanz zwischen Fadenkreuz und einer gegnerischen Spielfigur zu ermitteln. Momentan gehe ich hierfür wie folgt vor:
Delphi-Quellcode:
Dieser Code funktioniert auch soweit wunderbar, allerdings nur solange zwischen meiner Blickrichtung und dem Gegner ein maximaler Winkel von +/-90° eingehalten wird. Das Problem konnte ich auf die WorldToScreen() Funktion eingrenzen, welche indirekt von CallNodeTransform aufgerufen wird. Ihr Zweck ist es, die World Space Koordinaten in die 2D Bildschirm Koordinaten umzurechnen.
function GetCrosshairDistance2D(const Device: IDirect3DDevice9;
Player: TPlayerListItem): Integer; var ViewPort: TD3DViewport9; BoneVector, Crosshair: TD3DXVECTOR3; begin Result := $FFFFFFF; try BoneVector := CallNodeTransform(Device, Player, BONE_HEAD, true); Device.GetViewport(ViewPort); Crosshair.x := Viewport.Width / 2; Crosshair.y := Viewport.Height / 2; Result := GetVectorDistance(Crosshair, BoneVector, 1); except end; end; function GetVectorDistance(V1, V2: TD3DXVECTOR3; Units: Integer): Integer; var Difference: TD3DXVECTOR3; begin Difference.x := V2.x - V1.x; Difference.y := V2.y - V1.y; Difference.z := V2.z - V1.z; Result := Round(sqrt(Difference.x * Difference.x + Difference.y * Difference.y + Difference.z * Difference.z) / Units); end;
Delphi-Quellcode:
Vom Prinzip her erscheint es auch logisch, dass die Funktion fehlschlägt, da die berechneten Koordinaten bei einem Winkel von über +/-90° ja nicht mehr in den 2D Space des Bildschirms passen.
function WorldToScreen(const Device: IDirect3DDevice9; X, Y, Z: Single;
var Pos: TD3DXVECTOR3): Boolean; var VectorWorld: TD3DXVector3; ViewPort: D3DVIEWPORT9; Projection, View, World: TD3DXMATRIX; begin Result := false; try VectorWorld := D3DXVECTOR3(X, Y, Z); FillChar(ViewPort, SizeOf(D3DVIEWPORT9), #0); FillChar(Pos, SizeOf(TD3DXVECTOR3), #0); if (not Device.GetTransform(D3DTS_VIEW, View) = D3D_OK) then Exit; if (not Device.GetTransform(D3DTS_PROJECTION, Projection) = D3D_OK) then Exit; if (not Device.GetTransform(D3DTS_WORLD, World) = D3D_OK) then Exit; if (not Device.GetViewport(ViewPort) = D3D_OK) then Exit; D3DXVec3Project(Pos, VectorWorld, ViewPort, Projection, View, World); if (Pos.Z < 1) then begin Result := true; end; except raise Exception.Create('WorldToScreen failed'); end; end; Gibt es hier eine geschicktere Möglichkeit den rein 2-dimensionalen Abstand meines eigenen Fadenkreuzes zum Spieler zu berechnen? Eventuell über meine eigene Position und Rotation? Viele Grüße Zacherl |
AW: Vektordistanz Fadenkreuz zu Spieler (2D) berechnen
Ich muss gestehen, ich blicke gerade nicht wirklich durch deine Codefetzen, aber so prinzipiell: Dein Fadenkreuz hat 2D-Koordinaten? Dein Spieler 3D? Dann transformier doch die Spielerkoordinaten händisch in den Screenspace, und dann einfach den euklidschen Abstand. Vorausgesetzt, du willst den in Screenkoordinaten haben! Wenn nicht, wäre ggf. wichtig zu sagen, in welchem Kontext du den Abstand brauchst.
|
AW: Vektordistanz Fadenkreuz zu Spieler (2D) berechnen
Delphi-Quellcode:
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); var e1, e2, x1, y1, x2, y2, xR, yR, R, S: double; begin R:= 50; // Turm x1:= 100; y1:= 100; x2:= x; // "Monster" y2:= y; S:= Sqrt (Sqr(x2-x1) + Sqr(y2-y1)); e1:= (x2 - x1) / S; // cos e2:= (y2 - y1) / S; // sin xR:= x1 + R*e1; yR:= y1 + R*e2; Canvas.MoveTo(Round(x1), Round(y1)); Canvas.LineTo(Round(xR), Round(yR)); Caption:= IntToStr(Round(xR))+' '+IntToStr(Round(yR)); end; |
AW: Vektordistanz Fadenkreuz zu Spieler (2D) berechnen
Zitat:
Nun möchte ich den Spieler ermitteln, welcher den nähesten Abstand zum Fadenkreuz besitzt. Meine geposteten Funktionen haben einfach gesagt erstmal die X, Y Koordinaten des Fadenkreuzes ermittelt (Mitte des Bildschirms) und danach die 3D World Space Koordinaten des gengerischen Spielers in die Screen Koordinaten (2D) umgerechnet. Dann konnte ich über Phytagoras ganz einfach den Abstand ermitteln. Das Problem ist jetzt einfach, dass wenn ich einen Winkel von 90° zum gegnerischen Spieler überschreite, meine Berechnung von 3D in 2D logischerweise fehlschlägt. Der Grund ist ganz einfach, dass der Spieler nicht mehr sichtbar ist und somit seine 2D Koordinaten nicht mehr auf den Bildschirm passen würden. Konkret suche ich jetzt eine Methode, welche zuverlässig auch dann den nähesten am Fadenkreuz befindlichen Spieler ermittelt, wenn dieser sich in einem Winkel > 90° befindet, also theoretisch nicht mehr sichtbar ist. @Bjoerk: Deinen Codeschnipsel verstehe ich jetzt nicht ganz. So wie ich das sehe werden dort nur 2D Koordinaten verwendet. |
AW: Vektordistanz Fadenkreuz zu Spieler (2D) berechnen
Ahaaa! Es geht also um einen Winkelabstand, nicht um eine Räumliche Distanz! In dem Fall wäre es ggf. hilfreich, sich mal
![]() |
AW: Vektordistanz Fadenkreuz zu Spieler (2D) berechnen
Du sprichst chinesisch :D Aber ich werde die Begriffe mal googlen und schauen, ob ich damit was anfangen kann. Ob Winkelabstand in diesem Falle korrekt ist, weiß ich nicht. Es geht mir ja schon um eine räumliche Distanz. Aber eben nur im 2D Raum.
Ein Ansatz, den ich im Moment probiere, ist das Berechnen von Delta Yaw und Delta Pitch zwischen meiner Blickrichtung und der Blickrichtung, die ich hätte, wenn ich auf den gegnerischen Spieler schaue. Das scheint sogar schon teilweise zu funktionieren. Momentan beachte ich nur Yaw und lasse Pitch mal außen vor. |
AW: Vektordistanz Fadenkreuz zu Spieler (2D) berechnen
Das ist effektiv das selbe wie mein Vorschlag :) Nur, dass man mit den Kugelkoordinaten vermutlich billiger davon kommt, da man pro Gegner nur zwei trigonometrische Funktionen und 4 einfache Fallunterscheidungen machen muss*, und schon hast du "delta yaw + pitch". Wichtig ist dabei eben, dass die Distanz weg fällt, da so ein Projektil ja mit unendlicher Geschwindigkeit recht gut angenähert ist :)
Wenn man die beiden Winkel hat, kann man wieder recht einfach mittels "sqrt(yaw²+pitch²)" den gesamten Abstand berechnen, da die Projektion auf die Kugel im Grunde wieder ein 2D-Raum ist. Allerdings kein euklidscher, man müsste diesen Abstand dann für ein paar Fälle anpassen, da man zwischen -180° und 180° so eine doofe Stelle hat - es beschreibt ja beides die selbe Richtung, ist aber in Zahlen gesprochen recht weit weg voneinander. Man müsste also hier und da mal ein Pi addieren bzw. abziehen, aber für wann und wo genau ist mir das jetzt auch zu spät ;) *) Und natürlich insgesamt ein Mal (pro Frame / Testdurchgang) für einen Punkt in Blickrichtung mit etwas Abstand zum Spieler. |
AW: Vektordistanz Fadenkreuz zu Spieler (2D) berechnen
Ich bedanke mich schonmal recht herzlich für deine Hilfe. Werde mich wohl morgen nochmal melden :D Ich probiere jetzt erstmal die Sache mit sqrt() anhand von meinen wohl umständlich berechneten Delta Pitch und Delta Yaw Werten aus und schaue, inwiefern ich da noch ein Paar Anpassen vornehmen muss.
Wenn das soweit funktioniert bin ich sehr gespannt, ob ich mit den Kugelkoordinaten noch eine Optimierung erreichen kann :) Hier mal meine momentane Funktion zur Berechnung der Zielwinkel (absoluter Winkel / kein Delta):
Delphi-Quellcode:
Denke mal, hier kann man noch einiges an Optimierungen durchführen :D
procedure CalculateAimAngle(const Device: IDirect3DDevice9;
Player: TPlayerListItem; var Pitch, Yaw: Single); var Z, P, D, A: TD3DXVector3; T: Integer; begin Z := CallNodeTransform(Device, Player, BONE_HEAD, false); P := Camera.Position; // Pitch berechnen D3DXVec3Subtract(D, Z, P); A.x := 0; A.y := 1; A.z := 0; D3DXVec3Normalize(D, D); Pitch := ArcSin(Abs(D.x * A.x + D.y * A.y + D.z * A.z)); if ((Z.y - P.y) > 0) then Pitch := -Pitch; // Yaw berechnen D.x := Z.x - P.x; D.y := 0; D.z := Z.z - P.z; A.x := 0; A.y := 0; A.z := 1; D3DXVec3Normalize(D, D); Yaw := ArcCos(D.x * A.x + D.y * A.y + D.z * A.z); if ((Z.x - P.x) < 0) then Yaw := (2 * PI) - Yaw; // In Normalform umrechnen (Manchmal sind die Winkel Vielfache von 2*PI) T := Round(Yaw / (PI)); if (T = 1) then begin Yaw := Yaw - (2 * PI); end else begin Yaw := Yaw - (PI * T); end; end; |
AW: Vektordistanz Fadenkreuz zu Spieler (2D) berechnen
Das haut schonmal absolut nicht hin. :( Ich berechne erst den Winkel mit der oben geposteten Funktion und passe ihn dann an das aktuelle Vielfache von 2*PI an. Wenn man die Spielfigur paar Mal im Kreis bewegt, wird der Yaw Winkel nicht resettet, sondern erhöht sich einfach um eine komplette Umdrehung.
Zum anpassen des berechneten Winkels habe ich mir folgendes geschrieben:
Delphi-Quellcode:
procedure NormalizeAimAngle(var Pitch, Yaw: Single);
var T: Integer; begin T := Round(Camera.Yaw / (PI)); Yaw := Yaw + (PI * T); if (T mod 2) <> 0 then begin Yaw := Yaw + PI; end; end; |
AW: Vektordistanz Fadenkreuz zu Spieler (2D) berechnen
Meine Idee wäre, das Fadenkreuz als dreidimensionalen Strahl aufzufassen, der von der Kameraposition aus in die Blickrichtung verläuft. Der Abstand eines Spieler wäre dann der Abstand zu diesem Strahl. Ich wüsste jetzt aber auf die Schnelle nicht, wie man den Abstand eines Punktes von einem Strahl am einfachsten berechnet.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:01 Uhr. |
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