Erkennen einer sechseckigen Klickbox

17

Ich arbeite an einem Spiel , das verwickeln wird Keuchen Hexagone.

Gegenwärtig verwende ich ein Sechseckbild (alle Seiten sind gleich lang ... es passt in ein 50 x 50 Pixel großes Bild).

Ich bin etwas neu in C # und wirklich neu in XNA, aber gibt es eine einfache Methode, die ich aufrufen kann, anstatt eine gewundene if-Anweisung basierend auf Punkten und Winkeln auszuführen?

dich
quelle
Siehe gamedev.stackexchange.com/questions/6382/…, das die Hex-Klick-Erkennung implementiert.
Tim Holt
4
Ich habe total gegoogelt "keuch Sechsecke" Ich war wie "Was für ein Sechseck ist das ?!" Ich schätze, ich habe einen langsamen Tag.
MichaelHouse
2
Hmm, was passiert, wenn Sie nicht in das Sechseck, sondern in das Keuchen klicken?
Tim Holt
1
Abhängig von Ihren Anforderungen würde ein einfacher Kreis nur für einen Klickbereich ausreichen. Andernfalls müssen Sie einen Punkt in der Polygontechnik verwenden, z. B. die Wicklungssumme oder eine solche Summe.
PhilCK
Wenn die Hex-Karte nicht willkürlich gedreht werden soll, ist der Punkt auf dem Polygon ein MAJOR-Overkill. Was machst du mit einer Karte, die 1000x1000 Hexes ist? Überprüfen Sie jeden? RE: Kreise, sie werden nicht funktionieren. In der Nähe des Knotenpunkts zwischen drei Feldern überlappen sich drei Kreise. Kleinere Kreise, die vollständig innerhalb der Felder liegen, weisen Lücken auf, in denen legitime Klicks in keinem Kreis vorhanden sind.
Tim Holt

Antworten:

18

Ein Sechseck ist ein Rechteck mit abgeschnittenen Ecken. Ich habe dies so gesehen und gehört, dass die Civilization-Serie dies mit orthogonalen Karten tut, indem sie eine Bitmap mit einem weißen Raum (orthogonal oder hexagonal) und einem roten, grünen, blauen und gelben erzeugt Ecke. (Oder welche Farben du magst.)

Sechseckig: Hex MaskeoderBildbeschreibung hier eingeben

Senkrecht: Bildbeschreibung hier eingeben

Bestimmen Sie dann einfach, über welchem ​​Rechteck sich der Cursor befindet, und testen Sie die Farbe des Pixels an dieser Stelle. Wenn es weiß ist, schweben sie über diesem Raum. Jede andere Farbe wird einem Versatz zugeordnet und sie schweben stattdessen über diesem Sechseck. Dieser Weg ist effizient, benötigt wenig Geometrie und kann für jeden beliebigen Mosaikraum verwendet werden.

dlras2
quelle
Nur eine Anmerkung: Ein Sechseck hat 6 gleich lange Seiten. Keines der von Ihnen präsentierten Bilder enthält tatsächlich Sechsecke. Stattdessen enthalten sie 6 seitige Polygone. Ansonsten funktioniert diese Methode. Es ist wahrscheinlich langsamer als das Berechnen der Grenzen des Sechsecks, jedoch für größere Sechsecke, da diese Methode mehr Platz für größere Sechsecke benötigt (wenn Sie die Pixelgenauigkeit beibehalten möchten). Bei kleinen Sechsecken (und abhängig von der Hardware) ist diese Methode wahrscheinlich schneller als die Berechnung der Grenzen.
Olhovsky
9
Ein Sechseck ist ein beliebiges 6-seitiges Polygon. Was Sie denken, ist ein gleichseitiges Sechseck (tatsächlich denken Sie wahrscheinlich an ein reguläres Sechseck, das eine Art gleichseitiges und gleichwinkliges Sechseck ist)
Random832
Bitte beachten Sie, dass ich nicht gesagt habe, dass Ihre Antwort schlecht war. Ich denke, es ist eine gute Antwort und eine Lösung, die ihren Platz hat. Allerdings würde ich diese Methode nicht der Berechnung der Sechskantgrenzen vorziehen, da die Berechnung der Sechskantgrenzen auf jeder modernen Plattform eine wesentlich erweiterbarere Methode ist. Nehmen wir zum Beispiel an, Sie möchten die Sechseckgröße ändern - müssen Sie das Bild jetzt neu erstellen? Die Herstellung einer pixelgenauen Sechseckmaske ist ein Schmerz. Die Tatsache, dass Sie hier keine produziert haben, ist ein Beweis dafür, denke ich.
Olhovsky
2
@Olhovsky - Ich habe hier keine perfekte Sechseckmaske hergestellt, weil ich als Zivildienst in meinen Pausen während der Arbeit Fragen beantworte und kein Videospiel schreibe. Das OP suchte nach einer Lösung mit weniger Mathematik, und ich dachte, das wäre ordentlich, also dachte ich, ich würde sie teilen, weil es etwas ist, woran ich alleine sicherlich nicht gedacht hätte.
DLRAS2
18

Es gibt keine XNA-Methode, die einen Hexagon-Treffer-Test durchführt.

Dieser Artikel beschreibt, wie Sie eine Funktion schreiben, die den Test durchführt, und gibt Ihnen die Funktion:

So prüfen Sie, ob sich ein Punkt innerhalb eines Sechsecks befindet

Hier ist eine Zusammenfassung aus diesem Artikel: Sechskant-Klickfeld

Und die Funktion, die den Test durchführt, sieht folgendermaßen aus:

  1. Testen Sie den Begrenzungsrahmen frühzeitig um das Sechseck, wenn er es nicht schneidet.
  2. Transformiere den Punkt wie oben gezeigt in einen lokalen Quadranten.
  3. Führen Sie den folgenden isInsideTest für den lokalen Quadranten durch.

public function isInside(pos:Vec2Const):Boolean
{
    const q2x:Number = Math.abs(pos.x - _center.x);       
    const q2y:Number = Math.abs(pos.y - _center.y);
    if (q2x > _hori || q2y > _vert*2) 
        return false;
    return 2 * _vert * _hori - _vert * q2x - _hori * q2y >= 0;
}

Ausführliche Informationen finden Sie im Artikel.


Hier sind einige andere nützliche Quellen:

Olhovsky
quelle
1

Hier habe ich eine Methode, die verwendet werden kann, um Klicks innerhalb eines Polygons zu erkennen:

public bool PointInPolygon( Vector2 p, Vector2[] poly )
    {
        Vector2 p1, p2;
        bool inside = false;

        if( poly.Length < 3 )
        {
            return inside;
        }

        Vector2 oldPoint = new Vector2( poly[poly.Length - 1].X, poly[poly.Length - 1].Y );

        for( int i = 0; i < poly.Length; i++ )
        {
            Vector2 newPoint = new Vector2( poly[i].X, poly[i].Y );

            if( newPoint.X > oldPoint.X )
            {
                p1 = oldPoint;
                p2 = newPoint;
            }
            else
            {
                p1 = newPoint;
                p2 = oldPoint;
            }

            if( ( newPoint.X < p.X ) == ( p.X <= oldPoint.X )
                && ( (long)p.Y - (long)p1.Y ) * (long)( p2.X - p1.X )
                 < ( (long)p2.Y - (long)p1.Y ) * (long)( p.X - p1.X ) )
            {
                inside = !inside;
            }

            oldPoint = newPoint;
        }

        return inside;
    }

Sie müssen der Methode die Ecken Ihres Sechsecks in einem Vektor2-Array (poly) und die angeklickte Position (p) geben.

chr1s1202
quelle