Как стать автором
Обновить

Вращение 2D объекта по окружности

Привет, если ты читаешь эту статью, значит ты хочешь узнать ответ на вопрос «как работает вращение объекта в 2D ?»

Ты скорее всего знаешь что во всех современных движках, таких как Unity вращение осуществляется с помощью функции, но нам интересно, как можно написать алгоритм
вращения своими руками.

Если проще то наш алгоритм работает так.

Мы представляем окружность, где:

  1. Центр это точка, вокруг которой мы вращаем объект.
  2. Радиус — расстояние от центра до вращаемого объекта.

Итак, начнем.

Давайте взглянем на рисунок ниже:

image
Дано: длинна радиуса, координаты точки вращения, угол АОВ, АВ перпендикулярен оси ОХ.
Задача: Задать вращение точки А на 360 градусов с помощью формулы.
Рассмотрим: треугольник ОАВ:
угол ОВА — прямой => треугольник ОАВ — прямоугольный треугольник;
тогда:
гипотенуза = радиусу окружности с центром в точке О
угол поворота = от 1 до 360 градусов
тогда чтобы найти катеты ОВ и АВ нужно:
АВ = радиус * cos(угла поворота),
ОВ = $inline$радиус * sin(угла поворота)$inline$
Теперь когда мы знаем размеры катетов
мы составим формулу:
для координаты по x:$inline$позиция по x = радиус * cos(угла поворота) + начальная позиция по x$inline$,
и для координаты по y: $inline$позиция по y = радиус * sin(угла поворота) + начальная позиция по y$inline$

Давайте попробуем применить формулы:

import pygame, math

#colors
black = (0, 0, 0)

size = (500, 500)
screen = pygame.display.set_mode(size)

a = b = 200

clock = pygame.time.Clock()
FPS = 60

for i in range(1, 361, 3):
    clock.tick(FPS)
    angle = i * 3.14 / 180
    a = 100 * math.cos(angle) + 300
    b = 100 * math.sin(angle) + 300
    screen.fill(black)
    pygame.draw.circle(screen, (122, 0, 0), (int (a), int (b)), 6)
    pygame.display.update()


Не сложно догадаться что делает этот код, а именно вращает наш кружок по оси, но почему лишь один раз?

Давайте вспомним уроки геометрии в седьмом классе: градусная мера угла не может превышает 360 градусов.

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

import  pygame, math

#colors
red = (122 , 0, 0)
green = (0, 122, 0)
black = (0, 0, 0)

size = (500, 500)
screen = pygame.display.set_mode(size)

a = b = 200
i = 0

clock = pygame.time.Clock()
FPS  = 60

while True:
    clock.tick(FPS)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            quit()

    screen.fill(black)
    pygame.draw.circle(screen, red, (int (a), int (b)), 6)
    
    if i <= 360: # здесь мы ставим ограничения, что-бы питон не выдал нам ошибку. 
        angle = i * (3.14 / 180) # перевод из градусов в радианы
        a = 100 * math.cos(angle) + 300
        b = 100 * math.sin(angle) + 300
        i += 3 # здесь мы увеличиваем угол перемещения. 
        
    else:
        i = 0 #обнуляем i потому - что, углов > 360 градусов нет, а кружок прошел свой путь

Этот код позволяет вращать кружок по оси бесконечно.

Однако у этой формулы есть один недостаток: можно вращать объекты только на 1 оборот. Это значит что нам нужна другая формула.

Давайте улучшим нашу формулу: image

Дано:
треугольник ОАВ — прямоугольный
катет 1 = x1 — начальная координата X
катет 2 = y1 — начальная координата y

Задача:
улучшить формулу так, что-бы можно было вращать точку А на неизвестный угол.

Решение:
Из предыдущей задачи мы знаем что:
$inline$$inline$xPos = (lineLong * cos(a)) + StartPosX$inline$$inline$. => $inline$cos(a) = xPos — startPosX: (lineLong )$inline$

И теперь мы можем вывести формулу по нахождению угла a
$inline$yPos = (lineLong * sin(a)) + StartPosY$inline$ => $$display$$a = arccos((xPos — startPosX): lineLong)$$display$$.

А сейчас обновим нашу формулу и получим: $$display$$xPos = (lineLong * cos(a +b)) + startPosX$$display$$


Теперь у нас есть формула которая позволяет бесконечно вращать точку по окружности: $$display$$xPos = (lineLong * cos(a +arccos((xPos — startPosX): lineLong))) + startPosX$$display$$

Давайте напишем код, который будет вращать наш объект по нажатию на клавишу.

import pygame, math

#colors
black = (0, 0, 0)
green = (0, 122, 0)

size = (600, 600)
screen = pygame.display.set_mode(size)

a = b = 500
i = 0


clock = pygame.time.Clock()
FPS = 60

while True:
    clock.tick(FPS)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            quit()

    keys = pygame.key.get_pressed()
    if keys[pygame.K_RIGHT]:
        angle = i * 3.14 / 180
        l = math.acos((a - 400) / math.sqrt(500 ** 2 - 400 **2))
        int(l)
        a = (100 * math.cos(angle + l)) + 400
        b = (100 * math.sin(angle + l))  + 400
        i -= 3
    elif keys[pygame.K_LEFT]:
        angle = i * 3.14 / 180
        l = math.acos((a - 400) / math.sqrt(500 ** 2 - 400 **2))
        int(l)
        a = (100 * math.cos(angle + l))  + 400 # 400 - начальная точка по х и по у
        b = (100 * math.sin(angle + l))  + 400
        i += 3
    screen.fill(black)
    pygame.draw.circle(screen, green,  (int (a), int (b)), 6)
    pygame.display.update()

Примерно таком образом решается эта задача.

Надеюсь, ты смог извлечь полезную информацию из моего поста, желаю удачно применить полученные знания на практике
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.