Попытка повернуть управляемую ракету в pygame

Триггер - не моя сильная сторона, поэтому у меня возникают проблемы с попытками заставить мою управляемую ракету вращаться должным образом. Похоже, у меня все в порядке, хотя я все еще не на 100% доволен движением, поэтому я надеюсь, что исправив вращение, он тоже это исправит. Проблема в том, что мои ракеты не указывают на цель (игрока), и они также переворачиваются в определенной точке мимо цели. Вот код ... вращения просто не работают правильно.

def update(self):
    self.calcVect()
    self.calcPos()
    self.rotate()
    self.checkBounds()
    self.rect.center = (self.x, self.y)

def calcVect(self):
    self.vectX = self.targetX - self.x
    self.vectY = self.targetY - self.y
    self.length = math.sqrt((self.vectX*self.vectX)+(self.vectY*self.vectY)) 
    self.normX = self.vectX/self.length
    self.normY = self.vectY/self.length
    self.dx += self.normX*self.power
    self.dy += self.normY*self.power

def calcPos(self):
    self.x += self.dx*0.2
    self.y += self.dy*0.2

def rotate(self):
    radians = math.atan2(-self.vectY,self.vectX)
    radians %= 2*math.pi
    self.dir = math.degrees(radians)
    print self.dir
    oldCenter = self.rect.center
    self.image = pygame.transform.rotate(self.imageMissile, self.dir)
    self.rect = self.image.get_rect()
    self.rect.center = oldCenter

Рабочий код Вот новый рабочий код для всего класса. Выражение в конце этой строки позволяло правильно вращать "радианы = math.atan2 (self.vectX, self.vectY) - math.pi / 2", даже если изображение было горизонтальным в начале.

class GuidedMissile(pygame.sprite.Sprite):
def __init__(self, source):
    pygame.sprite.Sprite.__init__(self)
    self.screen = source.screen

    self.imageMissile = pygame.image.load("Images/missile.tga").convert()
    self.imageMissile.set_colorkey((0,0,255))
    self.image = self.imageMissile
    self.rect = self.image.get_rect()
    self.rect.center = source.rect.midbottom

    self.rect.inflate_ip(-15, -5)        

    self.x, self.y = self.rect.center
    self.X, self.Y = self.rect.center
    self.dx = 0
    self.dy = 0
    self.power = 3
    self.dir = 0

def update(self):
    self.player = goodSpritesOneGRP.sprite
    self.targetX, self.targetY = self.player.rect.center
    NX, NY = self.calcVect()
    self.calcVel(NX, NY)
    self.calcPos()
    self.rotate()
    self.checkBounds()
    self.rect.center = (self.x, self.y)

def calcVect(self):
    self.vectX = self.targetX - self.x
    self.vectY = self.targetY - self.y
    self.length = math.sqrt((self.vectX*self.vectX)+(self.vectY*self.vectY)) 
    if self.length == 0:
        self.normX = 0
        self.normY = 1
    else:
        self.normX = self.vectX/self.length
        self.normY = self.vectY/self.length
    return (self.normX, self.normY)

def calcVel(self,NX,NY ):
    self.dx += NX*self.power
    self.dy += NY*self.power            

def calcPos(self):
    self.x += self.dx*0.05
    self.y += self.dy*0.05

def rotate(self):
    radians = math.atan2(self.vectX, self.vectY)- math.pi/2
    radians %= 2*math.pi
    self.dir = math.degrees(radians)
    oldCenter = self.rect.center
    self.image = pygame.transform.rotate(self.imageMissile, self.dir)
    self.rect = self.image.get_rect()
    self.rect.center = oldCenter

def checkBounds(self):
    global guidedMissile
    screen = self.screen
    if self.x > screen.get_width():
        self.kill()
        guidedMissile -= 1
    if self.x < -100:
        self.kill()            
        guidedMissile -= 1
    if self.y > screen.get_height() + 100:
        self.kill()
        guidedMissile -= 1
    if self.y < -100:
        self.kill()            
        guidedMissile -= 1

person Aikman007    schedule 16.06.2013    source источник


Ответы (1)


Когда вы вызываете calcPos(), вам нужно пересчитать self.vectX и self.vectY, иначе ракета не наведется на цель. И не забудьте проверить self.length == 0

Вы можете исправить разбиение calcVect():

def calcVect(self):
    self.vectX = self.targetX - self.x
    self.vectY = self.targetY - self.y
    self.length = math.sqrt((self.vectX*self.vectX)+(self.vectY*self.vectY)) 
    if self.length != 0:
        normX = vectX/self.length
        normY = vectY/self.length

# Update velocity
def calcVel(self):
    self.dx += self.normX*self.power
    self.dy += self.normY*self.power

потом

def update(self):
    self.calcVect()
    self.calcVel()
    self.calcPos()
    self.calcVect()
    self.rotate()
    self.checkBounds()
    self.rect.center = (self.x, self.y)

Это решение работает, но я предлагаю вам написать общий метод calcVectTo(self, target), который возвращает унитарный вектор, указывающий на (target.x, target.y):

def calcVect(self, target):
    vectX = target.x - self.x
    vectY = target.y - self.y
    length = math.sqrt((vectX*vectX)+(vectY*vectY)) 
    if length == 0:
        normX = 0
        normY = 1
    else
        normX = vectX/length
        normY = vectY/length
    return (normX, normY)

Редактировать

Я не понимал, что цель зафиксирована, теперь это намного проще: вам нужно только вычислить vect при построении класса, перемещая calcVect с update на __construct (игнорируйте мою вторую реализацию calcVect):

class GuidedMissile(pygame.sprite.Sprite):
def __init__(self, source, target):
    ...
    self.calcVect()

def update(self):
    self.calcVel()
    self.calcPos()
    self.rotate()
    self.checkBounds()
    self.rect.center = (self.x, self.y)
person Federico    schedule 16.06.2013
comment
Ладно, похоже, проблема не устранена. Я включил весь класс в ваши поправки на случай, если проблема будет в другом месте оригинального поста. В очередной раз благодарим за помощь. - person Aikman007; 17.06.2013
comment
Думаю, проблема в том, как ракета ориентирована на изображении. Если он указывает вверх, то код radians = math.atan2(-self.vectY,self.vectX) - math.pi/2, потому что изображение уже повернуто на 90 градусов. Флип правильный, вы должны проверить столкновение с целью и что-то сделать (перестать вращаться, взорваться, ...). Кроме того, не смешивайте две реализации calcVect: выберите одну, иначе будет непонятно, как возвращается вектор. - person Federico; 17.06.2013
comment
Ракета указывает на положительный x, когда она вводится в pygame, я перевернул ее, чтобы указать отрицательный x, потому что это направление огня, но с приведенным выше кодом она либо указывает вверх, либо вниз и переворачивается при прохождении цели. Неважно, прокомментирую ли я метод переворота, потому что ракета просто указывает вниз, а не вверх. Re calcVect У меня есть 2 реализации, потому что у вас тоже есть 2, это ошибка или, может быть, я вас неправильно понял. Спасибо - person Aikman007; 17.06.2013
comment
Сейчас становится лучше. Я обнаружил, что прохожу позицию цели с помощью метода инициализации ракеты. Это означало, что положение целей обновлялось только при создании, и у меня было много ракет, которые бесцельно двигались. Тем не менее что-то работает не так, как должно, но приближается. - person Aikman007; 17.06.2013
comment
Да, я написал две разные реализации в одном ответе, я мог бы быть более понятным :) - person Federico; 17.06.2013
comment
Ой, это сильно изменилось ... Извините, но вы должны быть более конкретными - person Federico; 17.06.2013
comment
Да, я боялся, что могу упустить какую-то важную информацию, но трудно понять, что включить в код, имеющий отношение к проблеме. - person Aikman007; 17.06.2013
comment
Хорошо, вращение теперь работает благодаря вашему маленькому фрагменту кода math.atan2 (-self.vectY, self.vectX) - math.pi / 2. Я не уверен, почему это правильно сориентировало ракету, но это так. Я также удалил метод переворота. Спасибо, чувак, теперь мне нужно работать над ускорением, так как он медленно разворачивается и ускоряется обратно к цели. Окончательный код был включен в исходный пост. - person Aikman007; 17.06.2013