XNA'da altıgen tilemap toplama işlemini nasıl yapabilirim?


13

Bir altıgen tıklandığında ne zaman kontrol etmek gerekir altıgen döşenmiş bir harita var. Altıgenler aslında dokunmuyorlar, her biri arasında hafif bir boşluk var.

Herkes altıgen tıklandığında tüm şey karmaşık olmadan nasıl kontrol hakkında bilmek olabilir?

Yanıtlar:


13

Bu resme bir göz atın

altıgen ayrışma

Gördüğünüz gibi, x, y dikdörtgen koordinat sistemini altıgen olana eşlemek için nispeten sezgisel bir yol var.

"Düzgün" düzensiz altıgenler, yani her iki yönde orantısız olarak ölçeklendirilmiş normal altıgenlerden elde edilen altıgenler veya altıgenler içine yerleştirilmiş altıgenler hakkında konuşabiliriz (rotasyon-kesme yok).

Doğrultucu bir altıgen, daire içine alan dikdörtgenin yüksekliği ve genişliği ile yazıya dökülen dikdörtgenin genişliği ile tanımlanabilir. (W, W, h)

dikdörtgenleri yazma / sınırlama

Altıgen indeksi bulmanın en kolay yolu, alanı aşağıdaki gibi bölümlendirmektir:

uzay bölümü

Dikdörtgen genişliği w + (W - w) / 2 = (w + W) / 2, yüksekliği h / 2; yeşil dikdörtgenin genişliği (Ww) / 2'dir. Noktanın hangi dikdörtgenin içine düştüğünü bulmak kolaydır:

resim açıklamasını buraya girin

u ve v, i, j dikdörtgeninde noktanın nerede olduğunu gösteren hatırlatma koordinatlarıdır: w'yi kullanarak yeşil alanda (u <(Ww) / 2) olup olmadığımızı söyleyebiliriz.

eğer yeşil alandaysak altıgenin üst veya alt yarısında olup olmadığımızı bilmemiz gerekir: i ve j'nin her ikisi de eşitse veya her ikisi de tekse, üst yarıyız; aksi takdirde alt yarıyız.

Her iki durumda da, u ve v'yi değiştirmek 0 ve 1 arasında değişmektedir:

resim açıklamasını buraya girin

eğer alt yarıdayız ve v <u

veya

eğer üst yarıdaysak ve (1-v)> u

o zaman ben birer birer azalırız

İ i yatay altıgen indeks (sütun) ve j / 2 tamsayısının dikey altıgen indeks (satır) olduğunu görmek için garip ise j'yi bir azaltmalıyız.

resim açıklamasını buraya girin


Teşekkürler! Gerçekten yararlı, yeşil bölümün bölünmesi ile ortaya çıkan birkaç sorun vardı (i 1'den çıkarmalı mıyım veya çıkarmamalıyım), ama bunun altıgenlerin oryantasyonundan kaynaklandığını düşünüyorum. Hepsi çalışıyor, teşekkürler!
Joel

14

Düzenli altıgenlerin altı eksen simetrisi vardır, ancak altıgenlerinizin yalnızca iki simetri eksenine sahip olduğunu varsayacağım ( yani, tüm açılar tam olarak 60 derece değildir). Mutlaka sizinki tam simetriye sahip olmadığı için değil, başka biri için yararlı olabileceği için.

İşte bir altıgenin parametreleri. Merkezi O, en geniş genişliği, 2ayüksekliği 2bve üst kenarının uzunluğu 2c.

         Y ^
           |
       ____|____
      /  b |   |\
     /     |   | \
    /      |   |  \
---(-------+---+---)------>
    \     O|   c  / a      X
     \     |     /
      \____|____/
           |

Bu, orijini sol alt altıgenin ortasında olacak şekilde satır / sütun düzenidir. Kurulumunuz farklıysa, (x,y)bu duruma geri dönmek için koordinatlarınızı çevirin veya örneğin -yyerine kullanın y:

col 0
 | col 1
 |   | col 2
 |   |  |
 __  | __    __    __    __   
/  \__/  \__/  \__/  \__/  \__
\__/  \__/  \__/  \__/  \__/  \
/  \__/  \__/  \__/  \__/  \__/
\__/  \__/  \__/  \__/  \__/  \
/  \__/  \__/  \__/  \__/  \__/_ _ line 2
\__/  \__/  \__/  \__/  \__/  \ _ _ _ line 1
/ .\__/  \__/  \__/  \__/  \__/_ _ line 0
\__/  \__/  \__/  \__/  \__/

Aşağıdaki kod size altıgen içeren noktanın satırını ve sütununu verecektir (x,y):

static void GetHex(float x, float y, out int row, out int column)
{
  // Find out which major row and column we are on:
  row = (int)(y / b);
  column = (int)(x / (a + c));

  // Compute the offset into these row and column:
  float dy = y - (float)row * b;
  float dx = x - (float)column * (a + c);

  // Are we on the left of the hexagon edge, or on the right?
  if (((row ^ column) & 1) == 0)
      dy = b - dy;
  int right = dy * (a - c) < b * (dx - c) ? 1 : 0;

  // Now we have all the information we need, just fine-tune row and column.
  row += (column ^ row ^ right) & 1;
  column += right;
}

Yukarıdaki kodun bu IdeOne çalıştırmasında mükemmel altıgenler çizdiğini kontrol edebilirsiniz .


İdeOne'u ilk kez duydum, ama gerçekten kullanışlı görünüyor!
David Gouveia

@davidluzgouveia: evet, harika. Web veya bulut hizmetlerine düşkün değilim ama bu yardımcı olur.
sam hocevar

1

Altıgen alanın içine 3 döndürülmüş dikdörtgen sığdırabilirsiniz ve düzgün yapılırsa alanı tam olarak dolduracaktır. O zaman bu sadece üç dikdörtgenin çarpışmasını kontrol etmek meselesi olurdu.


1

Muhtemelen kutucuklar arasındaki tıklamaları kaldırmanıza gerek yoktur. Yani, aralarında mantıksal olarak olmaması gereken bir şeyle dolu geniş bir alandan bahsetmediğiniz sürece, fayanslar arasındaki boşlukların da tıklanabilir olmasına izin verirseniz, zarar vermez ve hatta oyuncuya yardımcı olabilir. tıklayın. (Diyelim ki altıgenler, aralarında insanlar gibi tıklanabilir diğer şeyler olan büyük bir haritada bulunan şehirlerdir)

Yukarıdakileri yapmak için, tüm altıgenlerin merkezlerini çizebilir ve ardından tüm altıgenlerin düzlemine tıklandığında fareye en yakın olanı bulabilirsiniz. Mozaik altıgenler düzlemindeki en yakın merkez her zaman üzerinde gezindiğiniz merkezle aynı olacaktır.


1

Benzer bir soruyu, aynı hedeflerle birlikte, Stack Overflow üzerinde, rahatlık için burada tekrar göndereceğim: (NB - tüm kod Java ile yazılmış ve test edilmiştir)

Üst üste bindirilmiş kare ızgaralı altıgen ızgara

Bu resim altıgen bir ızgaranın sol üst köşesini gösterir ve üst üste yerleştirilmiş mavi kare bir ızgaradır. Bir noktanın içinde hangi karelerin içinde olduğunu bulmak kolaydır ve bu da hangi altıgenin de kabaca bir yaklaşımını sağlar. Altıgenlerin beyaz kısımları, kare ve altıgen ızgaranın aynı koordinatları nerede paylaştığını, altıgenlerin gri kısımları ise nerede olmadığını gösterir.

Çözüm artık bir noktanın hangi kutuda olduğunu bulmak, daha sonra noktanın üçgenlerden herhangi birinde olup olmadığını kontrol etmek ve gerekirse cevabı düzeltmek kadar basit.

private final Hexagon getSelectedHexagon(int x, int y)
{
    // Find the row and column of the box that the point falls in.
    int row = (int) (y / gridHeight);
    int column;

    boolean rowIsOdd = row % 2 == 1;

    // Is the row an odd number?
    if (rowIsOdd)// Yes: Offset x to match the indent of the row
        column = (int) ((x - halfWidth) / gridWidth);
    else// No: Calculate normally
        column = (int) (x / gridWidth);

Bu noktada, noktamızın bulunduğu kutunun satırına ve sütununa sahibiz, daha sonra, noktamızın yukarıdaki altıgenlerden birinde olup olmadığını görmek için noktamızı altıgenin iki üst kenarına karşı test etmemiz gerekiyor:

    // Work out the position of the point relative to the box it is in
    double relY = y - (row * gridHeight);
    double relX;

    if (rowIsOdd)
        relX = (x - (column * gridWidth)) - halfWidth;
    else
        relX = x - (column * gridWidth);

Göreli koordinatlara sahip olmak bir sonraki adımı kolaylaştırır.

Düz bir çizgi için genel denklem

Yukarıdaki görüntüde olduğu gibi, noktamızın y değeri > mx + c ise , noktamızın çizginin üstünde olduğunu ve bizim durumumuzda, mevcut satırın ve sütunun üstündeki ve solundaki altıgen olduğunu biliyoruz. Java'daki koordinat sisteminin, her zaman matematikte olduğu gibi sol altta değil, ekranın sol üstünde 0'dan başladığını, dolayısıyla sol kenar için kullanılan negatif gradyan ve sağ için kullanılan pozitif gradyan olduğunu unutmayın.

    // Work out if the point is above either of the hexagon's top edges
    if (relY < (-m * relX) + c) // LEFT edge
        {
            row--;
            if (!rowIsOdd)
                column--;
        }
    else if (relY < (m * relX) - c) // RIGHT edge
        {
            row--;
            if (rowIsOdd)
                column++;
        }

    return hexagons[column][row];
}

Yukarıdaki örnekte kullanılan değişkenlerin hızlı bir açıklaması:

resim açıklamasını buraya girin resim açıklamasını buraya girin

m eğimdir , dolayısıyla m = c / halfWidth


NeoShamam'ın yukarıdakilere ilavesi

Bu SebastianTroy'un cevabına bir zeyilname. Bir yorum olarak bırakacaktım ama henüz yeterli üne sahip değilim.

Burada açıklandığı gibi bir eksenel koordinat sistemi uygulamak istiyorsanız: http://www.redblobgames.com/grids/hexagons/

Kodda küçük bir değişiklik yapabilirsiniz.

Onun yerine

// Is the row an odd number?
if (rowIsOdd)// Yes: Offset x to match the indent of the row
    column = (int) ((x - halfWidth) / gridWidth);
else// No: Calculate normally
    column = (int) (x / gridWidth);

bunu kullan

float columnOffset = row * halfWidth;
column = (int)(x + columnOffset)/gridWidth; //switch + to - to align the grid the other way

Bu, koordinatın (0, 2) doğrudan (0, 0) altında olmak yerine (0, 0) ve (0, 1) ile aynı çapraz sütunda olmasını sağlar.


Bunun altıgenler arasındaki boşlukları dikkate almadığını, ancak sorununuzu önemli ölçüde azaltmaya yardımcı olduğunu anlıyorum.
Troyseph

0

Tüm altıgenleriniz aynı oranlarda ve yerleştirme kullanılarak yapılırsa, çarpışmalar için bir tür yer paylaşımı kullanabilirsiniz, Bir altıgen için çarpışma katmanı

Ardından, tek yapmanız gereken çarpışma görüntüsünü altıgeninizin olduğu yere yerleştirmek, fare konumunu sol köşeye göre almak ve göreli konumun pikselinin beyaz OLMAMASI (yani bir çarpışma olduğu anlamına gelir).

Kod (test edilmedi):

bool IsMouseTouchingHexagon(Vector2 mousePosition, Vector2 hexagonPosition,
    Rectangle hexagonRectangle, Texture2D hexagonImage)
{
    Vector2 mousePositionToTopLeft = mousePosition - hexagonPosition;

    // We make sure that the mouse is over the hexagon's rectangle.
    if (mousePositionToTopLeft.X >= 0 && mousePositionToTopLeft.X < hexagonRectangle.Width && 
        mousePositionToTopLeft.Y >= 0 && mousePositionToTopLeft.Y < hexagonRectangle.Height)
    {
        // Where "PixelColorAt" returns the color of a pixel of an image at a certain position.
        if (PixelColorAt(hexagonImage, mousePositionToTopLeft) == Color.White)
        {
            // If the color is not white, we are colliding with the hexagon
            return true;
        }
    }

    // if we get here, it means that we did not find a collision.
    return false;
}

Tüm sürecin performansını artırmak için önceden bir dikdörtgen çarpışma kontrolü yapabilirsiniz (tüm altıgen görüntünüzün).

Kavramın anlaşılması ve uygulanması oldukça basittir, ancak yalnızca altıgenleriniz aynı olduğunda çalışır. Sadece bir dizi olası altıgen boyutunuz varsa da işe yarayabilir, bu da birden fazla çarpışma katmanına ihtiyacınız olacağı anlamına gelir.

Eğer çok daha eksiksiz ve tekrar kullanılabilir ne çok basit bir çözüm bulmak eğer (gerçekten çarpışmayı bulmak için matematik kullanarak) ama bence kesinlikle denemeye değer.


Yolunuzla, herhangi bir düzensiz şekil kümesi kullanabilir ve hepsine benzersiz bir renkle bir bindirme verebilir, ardından renkleri, bindirme tamponundan bir renk seçerek daha sonra bindirmeyi almak için haritanızı kullanarak nesnenin altında. Özellikle bu tekniği desteklediğimden değil, biraz fazla karmaşık geliyor ve IMHO'nun erken optimizasyon girişimi.
Troyseph

0

Üzerinde bir makale var Oyun Programlama Gems 7 adlandırılan Bees ve Oyuncular için: Altıgen Fayans Kolu nasıl tam olarak neye ihtiyacınız olacağını.

Ne yazık ki şu anda yanımda kitabımın bir kopyası yok, aksi halde biraz tarif edebilirdim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.