Zuverlässige Zielerfassung (Algorithmus)



  • Hey,

    ich programmiere momentan ein Spiel und versuche eine möglichst zuverlässige Zielerfassung zu programmieren.

    Konkret gibt es ein Fadenkreuz und anhand des Winkels zum Ziel kann ich bestimmen, ob der Spieler auf dieses oder das andere Ziel zielt.

    Das funktioniert soweit auch ganz gut, aber es kommt zu Problemen, wenn mehrere Ziele dich hintereinander stehen, denn dann wird unter Umständen plötzlich das hintere Ziel anvisiert, obwohl das hintere Ziel eh nicht zu treffen wäre, da es vom vorderen Ziel verdeckt wird.

    Das Problem lässt sich gut verstehen, denn ich berücksichtige nur den Winkel und nicht die Entfernung. Dadurch dass das andere Objekt ein Stück weiter weg steht, scheint es einen besseren Winkel zum Fadenkreuz zu haben. Das ist blöd.

    Die Lösung ist also, dass ich auch die Entfernung berücksichtigen muss. Die Frage ist wie ich das möglichst gut löse? Ich könnte die besten zwei Winkel raussuchen und dann schauen welches näher ist.

    Wäre das eine gute Idee? Habt ihr eine bessere/schönere Idee?

    Pseudo-Code der aktuellen Lösung:

    Ziel bestesZiel = null;
    float besterWinkel = Float.MinValue;
    
    foreach (Ziel in MöglicheZiele)
    {
     float winkel = Ziel.WinkelZumFadenkreuz();
     float distanz = Ziel.Distanz();
    
     if (winkel < besterWinkel)
     {
      bestesZiel = Ziel;
      besterWinkel = winkel;
     }
    }
    


  • ich nehme mal an dass WinkelZumFadenkreuz sowas ist wie

    return acos(dot(normalize(ziel_richtung),normalize(gegner_richtung)));
    

    in dem fall brauchst du das acos nicht, somit nicht den winkel es reicht der cosinus.

    return dot(normalize(ziel_richtung),normalize(gegner_richtung));
    

    nun, der trick der fuer dich funktionieren koennte, waere weiter entfernte objekte schlechter zu bewerten als nahe, dafuer koenntest du machen indem du die normalisierung der gegnerrichtung weglaesst

    return dot(normalize(ziel_richtung),gegner_richtung);
    

    wenn nun ein objekt zweimal weiter entfernt ist, wird es auch einen zweimal groesseren wert returnen.

    keine garantie dass dich das gluecklich macht 😉



  • Hallo rapso,

    dein Ansatz klingt interessant. Vielen Dank dafür!

    Allerdings bin ich mir nicht sicher, ob ich diesen so übernehmen kann, da ich es etwas ein wenig anders berechne. Bin leider auch kein Mathe-Ass und bin immer froh, wenn es überhaupt halbwegs funktioniert. Daher einfach mal der entsprechende Codeausschnitt:

    Vector3 vecToEnemy = c[i].transform.position - me.transform.position;
    
    vecToEnemy.Normalize();
    
    float angleToEnemy = Vector3.Dot (me.transform.forward, vecToEnemy);
    

    c ist ein Array und enthält alle Objekte.
    transform.position liefert die Koordinaten im 3D-Raum ( Vector3 ).
    me ist der Spieler.
    Vector3.Dot bildet das Kreuzprodukt von zwei Vector3 -Objekten.
    me.transform.forward gibt die normalisierte Rotation des Spielers zurück ( Vector3 ).

    Wenn ich jetzt einfach die Normalisierung von vecToEnemy weglasse, entspricht das dann wohl deinem Vorschlag?

    Ich kann es leider erst später testen. Ansonsten hätte ich einfach das gemacht. 😃



  • Wie sieht das Ziel aus? Kann man es mit einer Kugel annähern? Wenn ja, ist die Sache einfach: berechne den Vektor des Fadenkreuzes, und schneide diesen Strahl mit der Kugel*. Du bekommst als Ergebnis: a. Gibt es einen Schnittpunkt
    b. Wie weit ist dieser entfernt?
    Ergebnis sortieren und fertig.

    Das kannst du natürlich auch mit anderen geometrischen Körpern machen, aber Kugel ist halt verdammt einfach.

    * suche z.b. nach vector sphere intersection



  • Es geht um ein kleines Handyspiel und hierfür brauche ich die Zielhilfe, da es sonst auf dem Handy zu schwierig zu spielen wäre.

    Konkret will ich also, dass der Spieler auf ein Ziel grob zielt und das Spiel das erkennt und beim Treffen unterstützt. Das funktioniert bei entsprechend gut verteilten Gegnern auch absolut perfekt. Sobald sie aber hintereinenader stehen passt es nicht mehr und es wird unter Umständen der hintere Gegner anvisiert. Damit trifft man i.d.R. trotzdem auch noch den Gegner der davor steht, aber es ist einfach unschön und stört mich und könnte insbesondere später mal Probleme machen (Einbau von zielsuchenden Rakten, etc.).

    Ich muss also möglichst effizient (Handyspiel) den passenden Gegner auswählen. Natürlich könnte ich zu jedem Spieler einen Raycast senden und gucken, ob er ankommt und wie lang er ist, etc., aber das möchte ich gerne vermeiden, da es das Spiel unnötig langsamer machen wird.

    Ein netter mathematischer Ansatz wäre also ideal. Ich kann die Idee von rapso leider nicht einbauen, da ich es etwas anders gelöst habe als er angenommen hat und mir leider die mathematischen Kenntnisse fehlen es entsprechend anzupassen.



  • Ich habe mal etwas ganz dummes ausprobiert:

    float targetScore = vecToEnemy.sqrMagnitude * angle;
    

    Ich multipliziere einfach die Distanz mit dem Winkel und nehme das zur Bewertung des Ziels. Damit kann ein besserer Winkel eine größere Distanz rechtfertigen oder umgekehrt.

    Sieht vielversprechend aus. Konnte mit dieser Lösung noch keine Probleme feststellen, aber muss noch etwas weiter testen. 🙂



  • Muggy schrieb:

    Es geht um ein kleines Handyspiel und hierfür brauche ich die Zielhilfe, da es sonst auf dem Handy zu schwierig zu spielen wäre.

    Konkret will ich also, dass der Spieler auf ein Ziel grob zielt und das Spiel das erkennt und beim Treffen unterstützt. Das funktioniert bei entsprechend gut verteilten Gegnern auch absolut perfekt. Sobald sie aber hintereinenader stehen passt es nicht mehr und es wird unter Umständen der hintere Gegner anvisiert. Damit trifft man i.d.R. trotzdem auch noch den Gegner der davor steht, aber es ist einfach unschön und stört mich und könnte insbesondere später mal Probleme machen (Einbau von zielsuchenden Rakten, etc.).

    Ich muss also möglichst effizient (Handyspiel) den passenden Gegner auswählen. Natürlich könnte ich zu jedem Spieler einen Raycast senden und gucken, ob er ankommt und wie lang er ist, etc., aber das möchte ich gerne vermeiden, da es das Spiel unnötig langsamer machen wird.

    Ein netter mathematischer Ansatz wäre also ideal. Ich kann die Idee von rapso leider nicht einbauen, da ich es etwas anders gelöst habe als er angenommen hat und mir leider die mathematischen Kenntnisse fehlen es entsprechend anzupassen.

    Du weißt aber schon dass man den Schnittpunkt Kugel - Strahl durch eine quadratische Gleichung bestimmen kann? Das schafft selbst mein altes Nokia 😉


Log in to reply