Поворот тетрис блоков во время выполнения - PullRequest
0 голосов
/ 28 октября 2011

У меня есть класс tetronimo (блок тетриса), который имеет четыре типа QRect (названных first, second, third, fourth соответственно). Я рисую каждый тетронимо , используя функции типа build_tetronimo_L.

Они строят тетронимо в определенном направлении, но, как и в тетрисе, вы должны иметь возможность вращать тетронимо, я пытаюсь вращать тетронимо, вращая каждый отдельный квадрат тетронимо.

Я нашел следующую формулу для применения к каждой (x, y) координате определенного квадрата.

newx = cos (угол) * oldx - грех (угол) * oldy

newy = sin (угол) * oldx + cos (угол) * oldy

Теперь тип Qt QRect, похоже, имеет только функцию setCoords, которая принимает (x, y) координаты в верхнем левом углу и в нижнем правом углу точек соответствующего квадрата.

У меня есть пример (который, кажется, не дает правильного результата) вращения первых двух квадратов в моем тетронимо.

Может кто-нибудь сказать мне, как я должен правильно вращать эти квадраты, используя расчет вращения во время выполнения?

void tetromino::rotate(double angle) // angle in degrees
{
    std::map<std::string, rect_coords> coords = get_coordinates();
        // FIRST SQUARE
    rect_coords first_coords = coords["first"];

    //top left x and y
    int newx_first_tl = (cos(to_radians(angle)) * first_coords.top_left_x) - (sin(to_radians(angle)) * first_coords.top_left_y);
    int newy_first_tl = (sin(to_radians(angle)) * first_coords.top_left_x) + (cos(to_radians(angle)) * first_coords.top_left_y);

    //bottom right x and y
    int newx_first_bl = (cos(to_radians(angle)) * first_coords.bottom_right_x) - (sin(to_radians(angle)) * first_coords.bottom_right_y);
    int newy_first_bl = (cos(to_radians(angle)) * first_coords.bottom_right_x) + (sin(to_radians(angle)) * first_coords.bottom_right_y);

        //CHANGE COORDINATES
    first->setCoords( newx_first_tl, newy_first_tl, newx_first_tl + tetro_size,newy_first_tl - tetro_size);


        //SECOND SQUARE
    rect_coords second_coords = coords["second"];

    int newx_second_tl = (cos(to_radians(angle)) * second_coords.top_left_x) - (sin(to_radians(angle)) * second_coords.top_left_y);
    int newy_second_tl = (sin(to_radians(angle)) * second_coords.top_left_x) + (cos(to_radians(angle)) * second_coords.top_left_y);

        //CHANGE COORDINATES 
    second->setCoords(newx_second_tl, newy_second_tl, newx_second_tl - tetro_size, newy_second_tl + tetro_size);

first и second являются QRect типами. rect_coords - это просто struct с четырьмя int с, в которых хранятся координаты квадратов.

Расчеты первого квадрата и второго квадрата разные, так как я пытался понять это.

Надеюсь, кто-нибудь поможет мне разобраться?

(Да, я могу сделать это намного проще, но я пытаюсь извлечь уроки из этого)

Ответы [ 3 ]

3 голосов
/ 28 октября 2011

Это больше похоже на математический вопрос, чем на вопрос программирования. Просто вставьте значения, например, 90 градусов, чтобы угадать это. Для 90 градусов точка (x, y) отображается на (-y, x). Вы, вероятно, не хотите вращаться вокруг начала координат, но вокруг определенной точки поворота c.x, c.y. Для этого вам нужно сначала перевести, затем повернуть, а затем перевести обратно:

(x,y) := (x-c.x, y-c.y) // translate into coo system w/ origin at c
(x,y) := (-y, x)        // rotate
(x,y) := (x+c.x, y+c.y) // translate into original coo system
1 голос
/ 28 октября 2011

Перед вращением вы должны перевести так, чтобы фрагмент находился по центру в начале координат:

  1. Переведите ваш блок по центру 0, 0
  2. Поворот блока
  3. Переведите снова центр блока в x, y

Если вы вращаете без перевода, вы всегда будете вращаться вокруг 0, 0, но, поскольку блок не центрирован, он будет вращаться вокруг центра. Центрировать ваш блок довольно просто:

  1. Для каждой точки вычислите медиану X и Y, назовем ее m
  2. Отнимите m.X и m.Y до координат всех точек
  3. Поворот
  4. Снова добавить m.X и m.Y к точкам.

Конечно, вы можете использовать линейную алгебру и vector * matrix умножение, но, возможно, это слишком много:)


Перевод

Допустим, у нас есть сегмент с координатами A(3,5) B(10,15). Если вы хотите повернуть его вокруг его центра, мы сначала переведем его в наше происхождение. Давайте вычислим mx и my:

mx = (10 - 3) / 2
my = (15 - 5) / 2

Теперь мы вычисляем точки A1 и B1, переводящие сегмент так, чтобы он был отцентрирован к началу координат:

A1(A.X - mx, A.Y - my)
B1(B.X - mx, B.Y - my)

Теперь мы можем выполнить вращение A1 и B1 (вы знаете, как) . Затем мы должны снова перевести в исходное положение:

A = (rotatedA1.X + mx, rotatedA1.y + my)
B = (rotatedB1.X + mx, rotatedB1.y + my)

Если вместо двух баллов у вас есть n баллов, вы, конечно, делаете все за n баллов.

0 голосов
/ 28 октября 2011

Вы можете использовать Qt Графический вид , который выполняет все геометрические вычисления за вас.

Или вы просто хотите изучить основные линейные геометрические преобразования? Тогда чтение учебника по математике, вероятно, будет более подходящим, чем кодирование.

...