Как я могу равномерно разложить карты?

20

Учитывая набор игральных карт (прямоугольные изображения с шириной и высотой), как я могу повернуть и расположить каждую из них так, чтобы они выглядели как «веер», как если бы вы держали карточную руку в реальной жизни. Какая математика нужна для этого?

ОБНОВИТЬ

Вот финальная реализация браузера на JavaScript: https://cosmicrealms.com/blog/2013/03/16/hand-of-cards/ и http://jsfiddle.net/tyyvk/108/

Sembiance
источник
9
Сэр, у вас слишком много тузов в руке. Пожалуйста, отойди от стола.
Томас Андрле
Скрипту нужно обновить, чтобы использовать более позднюю версию MooTools.
Томдемует

Ответы:

30

теория

Поскольку вы не указали, на какой платформе вы это реализуете, я дам описание алгоритма без учета языка:

  1. Сначала кладите каждую карту друг на друга, давая им одинаковую начальную позицию.
  2. Затем для каждой карты примените вращение (обычно по центру вокруг одного из нижних углов , но перемещение этого источника по существу позволит вам настроить внешний вид вентилятора).
  3. Увеличивайте угол поворота между каждым вызовом , в зависимости от количества карточек и от того, насколько сильно вы хотите их разложить.

То, что вращение центрировано вокруг одного из нижних углов карты (или около угла), должно быть видно из его просмотра:

введите описание изображения здесь


Реализация

Что касается того, как реализовать это, это зависит от вашей платформы. В XNA вы можете просто использовать параметр Origin SpriteBatch.Drawдля изменения центра вашего вращения.

Вот что я получил с помощью следующего кода (с несколькими изменениями исходного положения, чтобы он выглядел лучше - в основном источник начинается около правого угла и заканчивается у левого угла):

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();

И результат:

введите описание изображения здесь

Дэвид Гувея
источник
7
Я бы добавил, что внешний вид можно настроить с помощью другого центра вращения, если вы хотите охватить меньшую дугу, вам следует использовать точку вращения, которая находится ниже карты.
aaaaaaaaaaaa
@eBusiness Вы правы, я добавлю это.
Дэвид Гувея
Большое спасибо, Дэвид! Я реализовал код, который вы показали в JavaScript здесь: jsfiddle.net/tyyvk/7
Sembiance