Jak mogę równomiernie rozłożyć karty?

20

Biorąc pod uwagę zestaw kart do gry (prostokątne obrazy o szerokości i wysokości), w jaki sposób mogę obracać i ustawiać każdą z nich, aby pojawiły się w układzie „wachlarza”, podobnie jak w prawdziwym życiu. Jaka matematyka jest do tego potrzebna?

AKTUALIZACJA

Oto końcowy etap implementacji przeglądarki w JavaScript: https://cosmicrealms.com/blog/2013/03/16/hand-of-cards/ i http://jsfiddle.net/tyyvk/108/

Sembiance
źródło
9
Wygląda na to, że masz za dużo asów. Odsuń się od stołu.
Tomas Andrle
Skrzypce należy zaktualizować, aby użyć późniejszej wersji MooTools.
tomdemuyt

Odpowiedzi:

30

Teoria

Ponieważ nie określiłeś, na jakiej platformie to wdrażasz, podam opis algorytmu w sposób niezależny od języka:

  1. Najpierw ułóż wszystkie karty jedna na drugiej, nadając im taką samą początkową pozycję.
  2. Następnie dla każdej karty zastosuj obrót (zwykle wyśrodkowany wokół jednego z dolnych rogów , ale przesunięcie tego pochodzenia w zasadzie pozwoli ci poprawić wygląd wentylatora).
  3. Zwiększ kąt obrotu między poszczególnymi połączeniami , w zależności od liczby kart i tego, jak chcesz je rozłożyć.

To, że obrót jest wyśrodkowany wokół jednego z dolnych rogów karty (lub w pobliżu rogu), powinno być oczywiste, patrząc na nią:

wprowadź opis zdjęcia tutaj


Realizacja

Jak to zaimplementować, zależy to od twojej platformy. W XNA możesz po prostu użyć parametru Origin, SpriteBatch.Drawaby zmienić środek obrotu.

Oto, co otrzymałem z następującym kodem (z kilkoma poprawkami do źródła, aby wyglądało lepiej - w zasadzie początek zaczyna się w pobliżu prawego rogu, a kończy w pobliżu lewego rogu):

int cards = 20;
float range = MathHelper.ToRadians(90);
float initialAngle = MathHelper.ToRadians(-45);
float increment = range / cards;
Vector2 leftCorner = new Vector2(0, texture.Height * 0.9f);
Vector2 rightCorner = new Vector2(texture.Width, texture.Height * 0.9f);
Vector2 fanPosition = new Vector2(400, 300);
spriteBatch.Begin();
for (float angle = 0; angle < range; angle+=increment)
{
    float cardAngle = initialAngle + angle;
    Vector2 cardOrigin = Vector2.Lerp(rightCorner, leftCorner, angle / range);
    spriteBatch.Draw(texture, fanPosition, null, Color.White, cardAngle, cardOrigin, 1f, SpriteEffects.None, 0f);
}
spriteBatch.End();

A wynik:

wprowadź opis zdjęcia tutaj

David Gouveia
źródło
7
Dodam, że wygląd można poprawić, używając innego środka obrotu, jeśli chcesz objąć mniejszy łuk, powinieneś użyć punktu obrotu leżącego poniżej karty.
aaaaaaaaaaaa
@eBusiness Masz rację, dodam to.
David Gouveia,
Wielkie dzięki David! Zaimplementowałem kod pokazany tutaj w JavaScript: jsfiddle.net/tyyvk/7
Sembiance