Teoria
Ponieważ nie określiłeś, na jakiej platformie to wdrażasz, podam opis algorytmu w sposób niezależny od języka:
- Najpierw ułóż wszystkie karty jedna na drugiej, nadając im taką samą początkową pozycję.
- 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).
- 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ą:

Realizacja
Jak to zaimplementować, zależy to od twojej platformy. W XNA możesz po prostu użyć parametru Origin, SpriteBatch.Draw
aby 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:
