Поиск подходящих модификаторов координат X / Y с заданным углом в Python / Pygame - PullRequest
3 голосов
/ 21 мая 2019

Я пытаюсь заставить спрайт двигаться прямо к мышке, используя угол между ними. Этот угол находится с помощью функции atan2. Хотя этот угол отлично работает для вращения спрайта в направлении мыши, спрайт перемещается в неправильных направлениях в зависимости от квадранта данного угла. Иногда он будет зависать в одном квадранте или двигаться прямо напротив мыши.

Я использую базовые функции Trig, чтобы найти угол и вычислить правильные добавления к переменным X и Y спрайта. Также важно отметить, что угол, который я вычисляю, хотя он не работает для движения, отлично работает для вращения. Странно, что я пропускаю X-разность между двумя точками, а затем Y-разность, которая противоположна тому, как предполагается обрабатывать обратную касательную функцию. Поэтому я даже не уверен, как этот угол заставляет вращение работать правильно.

Я попытался передать разницу Y и X (в этом порядке) в функцию atan2. Однако это приводит к неправильному повороту моего спрайта, что наводит меня на мысль о том, что угол в целом также неверен. Я также попытался следовать наряду с многочисленными другими программами, которые используют те же формулы, что и я. Однако они не работают, даже когда я изменяю порядок аргументов на функцию atan2, чтобы соответствовать программам примера.

def main():

ExitLoop = False

image = IMAGELOADER.AllImages["Fighter1"]
image2 = IMAGELOADER.AllImages["Fighter2"]
Fighter1 = FighterClass.Fighter(image,(700,700))
Fighter2 = FighterClass.Fighter(image2,(300,300))
while not ExitLoop:

    ScreenController.Refresh()
    mouse_pos = pygame.mouse.get_pos()
    Fighter2.set_x(mouse_pos[0]-32)
    Fighter2.set_y(mouse_pos[1]-32)
    angle = math.atan2(Fighter1.get_x()-mouse_pos[0]+32, Fighter1.get_y()-mouse_pos[1]+32)
    degrees_angle = math.degrees(angle)
    Fighter1.rotate(degrees_angle)
    xval = Fighter1.get_x()
    yval = Fighter1.get_y()
    speed = Fighter1.get_speed()
    changex = (speed*math.cos(angle))
    changey = (speed*math.sin(angle))
    Fighter1.set_x(xval+changex)
    Fighter1.set_y(yval+changey)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            ExitLoop = True
    ScreenController.Draw(Fighter1.get_image(),Fighter1.get_rect(),False)
    ScreenController.Draw(Fighter2.get_image(),Fighter2.get_rect(),False)
    ScreenController.DisplayUpdate()
    clock.tick(60)

Код класса (относится к классу бойцов)

import pygame
import WoodysFunctions
class Fighter(pygame.sprite.Sprite):
    def __init__(self,image,XnY):
        pygame.sprite.Sprite.__init__(self)
        self.image = image
        self.__image_source = image
        self.rect = self.image.get_rect()
        self.__mask = pygame.mask.from_surface(self.image)
        self.rect.x = XnY[0]
        self.rect.y = XnY[1]
        self.__speed = 1
    def get_image(self):
        return self.image
    def get_rect(self):
        return self.rect
    def get_mask(self):
        return self.__mask
    def get_x(self):
        return self.rect.x
    def get_y(self):
        return self.rect.y
    def get_speed(self):
        return self.__speed

    def set_image(self,value):
        self.image = value
    def set_rect(self,value):
        self.__rect = value
    def set_mask(self,value):
        self.__mask = value
    def set_x(self,value):
        self.rect.x = value
    def set_y(self,value):
        self.rect.y = value
    def set_speed(self,value):
        self.__speed = value

    def rotate(self,angle):
        old_center = self.rect.center
        self.image = pygame.transform.rotate(self.__image_source,angle)
        self.rect = self.image.get_rect()
        self.rect.center = old_center

Ожидаемый результат: Sprite движется прямо к мыши

Фактическое поведение: спрайт движется в неправильных направлениях, при этом поведение демонстрирует закономерности, зависящие от квадранта расчетного угла.

Edit: Я изменил программу так, чтобы переменные X и Y спрайта сохранялись в переменных, отличных от объекта rect Это предотвращает десятичное усечение. Я также пересчитал угол между спрайтом и указателем мыши после завершения кода поворота. При пересчете разностные параметры X и Y меняются местами, чтобы соответствовать обратной функции тангенса вместо обратной функции котангенса. Этот пересчитанный угол используется для углового перемещения, а первый угол с разницей X, пройденной первым, используется для вращения. Важно отметить, что после того, как я вычислил переменные changeX и changeY, используя пересчитанный угол (с переданной разницей Y), я умножил их на -1, так как в противном случае спрайт отойдет от указателя мыши.

1 Ответ

2 голосов
/ 21 мая 2019

Я не могу быть уверен на 100%, но я думаю, что проблема в том, что pygame.Rect сохраняет положение в виде целых чисел, потому что он должен хранить координаты и размеры в пиксельных единицах, и, конечно, вы не можете рисовать половину пикселя.

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

def set_x(self,value):
    self.rect.x = value

Здесь, если value равно 1,4, self.rect.x становится равным 1. Таким образом, выпотеря «точности».

Эта потеря точности распространяется на каждую итерацию основного цикла (каждого кадра), что приводит к неожиданному направлению движения.

Лучшее решение - сохранить все ваши значенияв отдельной структуре данных и обновите атрибут rect только для рисования на экране.

...