2016-04-24 27 views
3

ProblemVertical Hex Grid: Get x Ringe von Fliesen mit einem spezifischen Koordinaten umgebenden

Was ich versuche, ist x Anzahl der Ringe von einem bestimmten Punkt zu tun bekommen, und speichern Sie diese Ringe in einem List<List<HexCoordinate>> wo die inneren Liste ist eine Liste aller Hexen in diesem Ring und HexCoordinate ist eine Struktur definiert unter

Idealerweise möchte ich in der Lage sein, die Koordinate zu spezifizieren, und wie viele Ruftöne möchte ich suchen und den Algorithmus greifen lassen die Fliesen für mich.

Bilder und Versuche

Ich habe ein Vertikal (Flat Top) Hex Gitter, das wie dieses Overall Hex Grid

In Code sieht, jede Platte durch eine einfache HexCoordinate Struktur dargestellt wird GitHub

public struct HexCoordinate : IEquatable<HexCoordinate> 
{ 
    public int X { get; private set; } 
    public int Y { get; private set; } 

    public HexCoordinate(int x, int y) 
    { 
     X = x; 
     Y = y; 
    } 

    public HexCoordinate North() => this + new HexCoordinate(0, -1); 
    public HexCoordinate South() => this + new HexCoordinate(0, 1); 

    public HexCoordinate West() => this + new HexCoordinate(-1, 0); 
    public HexCoordinate East() => this + new HexCoordinate(1, 0); 

    public HexCoordinate NorthWest() => this + new HexCoordinate(-1, -1); 
    public HexCoordinate NorthEast() => this + new HexCoordinate(1, -1); 

    public HexCoordinate SouthWest() => this + new HexCoordinate(-1, 1); 
    public HexCoordinate SouthEast() => this + new HexCoordinate(1, 1); 

    public bool Equals(HexCoordinate other) 
    { 
     return X == other.X && 
       Y == other.Y; 
    } 
    public static HexCoordinate operator +(HexCoordinate one, HexCoordinate two) 
    { 
     return new HexCoordinate(one.X + two.X, one.Y + two.Y); 
    } 
} 

Für mein Beispiel insbesondere, habe ich ein Bild, das ich gezeichnet habe, um dieses Problem selbst herauszufinden Close Up Example

Was ich

versucht haben und weil ich zeigen muss, was ich bereits versucht haben, das ist, was ich bisher

public const int MAX_RINGS = 3; 
public List<List<HexCoordinate> GetsRingsWithinHex(HexCoordinate coordinate, int maxRings = MAX_RINGS) 
{ 
    // Attempt One Pseudocode 
    // reference: http://gamedev.stackexchange.com/questions/51264/get-ring-of-tiles-in-hexagon-grid 
    // int ring = 1 
    // Travel around the ring by traversing N,SE,S,SW,NW,N,NE multiplied by the ring number 
    // ring++ 
    //  Travel Around ring again 
    //  cont until desired ring... 

    var hexRings = new List<List<HexCoordinate>>(); 

    // Add in the current hex to the list 
    var currentHex = new List<HexCoordinate>(); 
    currentHex.add(coordinate); 
    hexRings.Add(currentHex); 

    // Now go through and add the other rings 
    while (hexRings.Count <= maxRings) 
    { 
     var ring = new List<HexCoordinate>(); 
     HexCoordinate tempCoordinate = coordinate; 
     int currentRingNumber = hexRings.Count; 

     // We start off by going north to the correct ring, and then adding it to our list 
     for (int i = 0; i < currentRingNumber; i++) 
     { 
      tempCoordinate = tempCoordinate.North(); 
     } 
     ring.add(tempCoordinate); 

     // After that, we proceed to go clockwise around the ring until we come back to the start 
     for (int i = 0; i < currentRingNumber; i++) 
     { 
      tempCoordinate = tempCoordinate.SouthEast(); 

      // If the ring is an odd number, you need to re-align the coordinates back to where whey should be 
      if (IntExtensions.IsOdd(i)) tempCoordinate = tempCoordinate.North(); 

      ring.add(tempCoordinate); 
     } 

     // The rightmost segment is east because we can go straight down the required number of times 
     for (int i = 0; i < currentRingNumber; i++) 
     { 
      tempCoordinate = tempCoordinate.South(); 
      ring.add(tempCoordinate); 
     } 

     // We utilize Current Ring - 1 because we only want this to run on rings that are greater than 1 
     for (int i = 0; i < currentRingNumber - 1; i++) 
     { 
      tempCoordinate = tempCoordinate.SouthWest(); 
      ring.add(tempCoordinate); 
     } 

     // Coming into this statement, we are now at the bottom 3 coordinates. 
     // Since our grid is laid out vertically, we can assume that these three hexes will be directly west of eachother 
     // So we only have to go west twice to make our way to the next north segment 
     for (int i = 0; i < 2; i++) 
     { 
      tempCoordinate = tempCoordinate.West(); 
      ring.add(tempCoordinate); 
     } 

     // We utilize Current Ring - 1 because we only want this to run on rings that are greater than 1 
     for (int i = 0; i < currentRingNumber - 1; i++) 
     { 
      tempCoordinate = tempCoordinate.NorthWest(); 
      ring.add(tempCoordinate); 
     } 

     // The left most segment is easy because we can just go straight up 
     for (int i = 0; i < currentRingNumber; i++) 
     { 
      tempCoordinate = tempCoordinate.North(); 
      ring.add(tempCoordinate); 
     } 

     // We utilize Current Ring - 1 because we only want this to run on rings that are greater than 1 
     for (int i = 0; i < currentRingNumber - 1; i++) 
     { 
      tempCoordinate = tempCoordinate.NorthEast(); 

      // If the ring is an even number, you need to re-align the coordinates back to where whey should be 
      if (IntExtensions.IsEven(i)) tempCoordinate = tempCoordinate.South(); 

      ring.add(tempCoordinate); 
     } 

     // Finally, we add the ring to our system rings and loop until we no longer fit the criteria 
     hexRings.Add(ring); 
    } 

    return hexRings; 
} 

versucht haben und es wird, falls erforderlich, Hier ist meine IntExtensions

Mein aktuelles Problem ist, dass dieser Algorithmus für t arbeitet Der erste und der zweite Ring, aber sobald es zum dritten Ring kommt (und vermutlich weiter, wenn ich es über 3 hinaus lief) beginnen die Koordinaten entlang des Bodens und der Ecken, um 1 versetzt zu werden, wie man an der Ausgabe in meinem sehen kann Konsole unten (mit dem, was sie von Hand manuell bearbeitet werden sollte)

Ring 0 - System 5, 5 

Ring 1 - System 5, 4 
Ring 1 - System 6, 5 
Ring 1 - System 6, 6 
Ring 1 - System 5, 6 
Ring 1 - System 4, 6 
Ring 1 - System 4, 5 

Ring 2 - System 5, 3 
Ring 2 - System 6, 4 
Ring 2 - System 7, 4 
Ring 2 - System 7, 5 
Ring 2 - System 7, 6 
Ring 2 - System 6, 7 
Ring 2 - System 5, 7 
Ring 2 - System 4, 7 
Ring 2 - System 3, 6 
Ring 2 - System 3, 5 
Ring 2 - System 3, 4 
Ring 2 - System 4, 4 

Ring 3 - System 5, 2 
Ring 3 - System 6, 3 
Ring 3 - System 7, 3 
Ring 3 - System 8, 4 
Ring 3 - System 8, 5 
Ring 3 - System 8, 6 
Ring 3 - System 8, 7 
Ring 3 - System 7, 8 //(Should be 7, 7) 
Ring 3 - System 6, 9 //(Should be 6, 8) 
Ring 3 - System 5, 9 //(Should be 5, 8) 
Ring 3 - System 4, 9 //(Should be 4, 8) 
Ring 3 - System 3, 8 //(Should be 3, 7) 
Ring 3 - System 2, 7 
Ring 3 - System 2, 6 
Ring 3 - System 2, 5 
Ring 3 - System 2, 4 
Ring 3 - System 3, 4 //(Should be 3, 3) 
Ring 3 - System 4, 3 

würde jemand in der Lage sein zu helfen, mich in die richtige Richtung, oder geben sie mir mit einem Algorithmus, der mir erlauben würde, bekommen die Ringe von Flüche? Ich habe persönlich seit ungefähr anderthalb Tagen an diesem Problem festgemacht, und ich kann es mir nicht vorstellen.

+1

Der erste Gedanke, der mir in den Sinn kam, war: Warum nicht ein anderes Nummerierungsschema für das Gitter verwenden? Doppelte Auflösung. Verhexungen in der ersten Spalte beginnen mit 0 in 2er-Schritten, Verhexungen in der zweiten Spalte beginnen mit 1 in 2er-Schritten. Daher befinden sich Ihre Hexes auf einem regelmäßigen quadratischen Raster mit doppelter Auflösung. Dann können Sie vielleicht den Bresenham-Kreis-Algorithmus verwenden, um schnell zu entscheiden, ob ein Hex mit einem Kreis mit Radius 2 * -Ring geschnitten wird. – BitTickler

+0

Meine F # -Port von Wikipedia Bresenham C-Routine sieht nicht wirklich gut :) Aber aus meinen aktuellen Untersuchungen bin ich versucht zu denken, dass der Ansatz, den ich oben abgebildet ist, grundsätzlich machbar ist. Hier führt Ihr erwarteter ring3 zu meinem "Double Resolution" -Ansatz. Es wurden keine Sechsecke sondern Kreise dargestellt;) http://imgur.com/kZtWw8S – BitTickler

+0

Sie müssen ** LSB ** von 'x' und' y' Koordinaten berücksichtigen und die Position entsprechend korrigieren.Sie wollen keine Kreise sondern Sechsecke, also ist Bresenham unbrauchbar. Stattdessen sucht man nach allen Hexen mit 1, 2, 3, 4 ... Zellen vom Ursprung, also wäre 'A *' besser. Werfen Sie einen Blick auf [Verbesserung der Leistung der Klickerkennung in einem isometrischen Gitter mit gestaffelten Spalten] (http://stackoverflow.com/a/35917976/2521214), insbesondere 'cell2scr' und' scr2cell' für das, was ich mit LSB von 'x meine, y 'Koordinatenkorrekturen (Es ist ein quadratisches Gitter, aber das Problem ist dasselbe). btw nette Skizze – Spektre

Antwort

0

In Ordnung, also denke ich, dass ich eine Lösung für mein Problem gefunden haben könnte. Ich habe es bis zu 4 Ringe getestet und es gibt mir alle korrekten Hexen in den entsprechenden Ringen.

public List<List<HexCoordinate>> GetsRingsSurroundingHex(HexCoordinate coordinate, int maxRings) 
    { 
     // idea reference: http://gamedev.stackexchange.com/questions/51264/get-ring-of-tiles-in-hexagon-grid 
     // int ring = 1 
     // Travel around the ring by traversing N,SE,S,SW,NW,N,NE multiplied by the ring number 
     // ring++ 
     //  Travel Around ring again 
     //  cont until desired ring... 

     var hexRings = new List<List<HexCoordinate>>(); 

     // Add in the current hex to the list 
     var currentHex = new List<HexCoordinate>(); 
     currentHex.Add(coordinate); 
     hexRings.Add(currentHex); 

     // Now go through and add the other rings 
     while (hexRings.Count <= maxRings) 
     { 
      var ring = new List<HexCoordinate>(); 
      HexCoordinate tempCoordinate = coordinate; 
      int currentRingNumber = hexRings.Count; 

      // We start off by going north to the correct ring, and then adding it to our list 
      for (int i = 0; i < currentRingNumber; i++) 
      { 
       tempCoordinate = tempCoordinate.North(); 
      } 
      ring.Add(tempCoordinate); 

      // After that, we proceed to go clockwise around the ring until we come back to the start 
      for (int i = 0; i < currentRingNumber; i++) 
      { 
       tempCoordinate = tempCoordinate.SouthEast(); 

       // If the ring is an odd number, you need to re-align the coordinates back to where whey should be 
       if (IntExtensions.IsOdd(i)) tempCoordinate = tempCoordinate.North(); 

       ring.Add(tempCoordinate); 
      } 

      // The rightmost segment is east because we can go straight down the required number of times 
      for (int i = 0; i < currentRingNumber; i++) 
      { 
       tempCoordinate = tempCoordinate.South(); 
       ring.Add(tempCoordinate); 
      } 

      // We utilize Current Ring - 1 because we only want this to run on rings that are greater than 1 
      for (int i = 0; i < currentRingNumber - 1; i++) 
      { 
       if (currentRingNumber.IsEven()) 
       { 
        if (i.IsEven()) 
         tempCoordinate = tempCoordinate.SouthWest(); 
        else 
         tempCoordinate = tempCoordinate.West(); 
       } 
       else 
       { 
        if (i.IsEven()) 
         tempCoordinate = tempCoordinate.West(); 
        else 
         tempCoordinate = tempCoordinate.SouthWest(); 
       } 

       ring.Add(tempCoordinate); 
      } 

      // Coming into this statement, we are now at the bottom 3 coordinates. 
      // Since our grid is laid out vertically, we can assume that these three hexes will be directly west of each other 
      // So we only have to go west twice to make our way to the next north segment 
      for (int i = 0; i < 2; i++) 
      { 
       tempCoordinate = tempCoordinate.West(); 
       ring.Add(tempCoordinate); 
      } 

      // We utilize Current Ring - 1 because we only want this to run on rings that are greater than 1 
      for (int i = 0; i < currentRingNumber - 1; i++) 
      { 
       if (i.IsEven()) 
        tempCoordinate = tempCoordinate.NorthWest(); 
       else 
        tempCoordinate = tempCoordinate.West(); 

       ring.Add(tempCoordinate); 
      } 

      // The left most segment is easy because we can just go straight up 
      for (int i = 0; i < currentRingNumber; i++) 
      { 
       tempCoordinate = tempCoordinate.North(); 
       ring.Add(tempCoordinate); 
      } 

      // We utilize Current Ring - 1 because we only want this to run on rings that are greater than 1 
      for (int i = 0; i < currentRingNumber - 1; i++) 
      { 
       if (currentRingNumber.IsEven()) 
       { 
        if (i.IsEven()) 
         tempCoordinate = tempCoordinate.East(); 
        else 
         tempCoordinate = tempCoordinate.NorthEast(); 
       } 
       else 
       { 
        if (i.IsEven()) 
         tempCoordinate = tempCoordinate.NorthEast(); 
        else 
         tempCoordinate = tempCoordinate.East(); 
       } 

       ring.Add(tempCoordinate); 
      } 

      // Finally, we add the ring to our system rings and loop until we no longer fit the criteria 
      hexRings.Add(ring); 
     } 

     return hexRings; 
    }