Pygame 图像旋转非常 wobbly/unstable

Pygame Image rotation very wobbly/unstable

我正在开发一款游戏,玩家输入图形 f(x) = ... 并绘制图形。所有这些都可以无缝运行。火箭应该沿着这条路径旋转,所以它会停留在上面。我正在使用 math.degrees(math.atan2(-dy, dx)) 来找到它应该旋转到的 2 个点之间的角度。我旋转图像:

def blit_rotate_center(self, surf, topleft, rot_angle):
    rotated_image = pygame.transform.rotate(self.image, rot_angle)
    new_rect = rotated_image.get_rect(center=self.image.get_rect(topleft=topleft).center)
    surf.blit(rotated_image, new_rect)
    self.rect = new_rect

它确实有点用,但有很多奇怪和故障的旋转。

提前致谢! 主循环:

while True:
for event in pygame.event.get():
    if event.type == pygame.QUIT:
        print(easy_high_score, med_high_score, hard_high_score)
        pygame.quit()
        sys.exit()

    if event.type == pygame.MOUSEBUTTONDOWN:
        if input_rect.collidepoint(event.pos):
            box_active = True
        else:
            box_active = False

        if launch_rect.collidepoint(event.pos) and not box_active:
            launch = True
            launch_active = True
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_ESCAPE:
            box_active = False
        if box_active:
            if event.key == pygame.K_BACKSPACE:
                if user_text == "Invalid Input":
                    user_text = ""
                else:
                    user_text = user_text[:-1]
                pt_list = []
                coord_list = []
                draw = False
            elif event.key == pygame.K_RETURN:
                draw = True
                if user_text == "Alim":
                    end_planet_pos = (1920, 540)
                    start_planet_pos = (0, 540)
                    cp_pos = (960, 540)
            else:
                user_text += event.unicode
                pt_list = []
                coord_list = []

screen.blit(bg_list[bg_index], (0, 0))
start.blit_start(start_planet_pos, (500, 500))
end.blit_start(end_planet_pos, (500, 500))

if difficulty == 0:
    enemy0.blit_start(enemy0_pos, (200, 200))
    if pygame.sprite.collide_mask(enemy0, checkpoint):
        enemy0_pos = (random.randint(200, 1720), random.randint(200, 880))

if difficulty == 1:
    enemy0.blit_start(enemy0_pos, (200, 200))
    enemy1.blit_start(enemy1_pos, (200, 200))
    if pygame.sprite.collide_mask(enemy0, checkpoint):
        enemy0_pos = (random.randint(200, 760), random.randint(200, 880))
    if pygame.sprite.collide_mask(enemy1, checkpoint):
        enemy1_pos = (random.randint(1160, 1720), random.randint(200, 880))
if difficulty == 2:
    enemy0.blit_start(enemy0_pos, (200, 200))
    enemy1.blit_start(enemy1_pos, (200, 200))
    enemy2.blit_start(enemy2_pos, (200, 200))
    if pygame.sprite.collide_mask(enemy0, checkpoint):
        enemy0_pos = (random.randint(200, 760), random.randint(200, 880))
    if pygame.sprite.collide_mask(enemy1, checkpoint):
        enemy1_pos = (random.randint(1160, 1720), random.randint(200, 880))
    if pygame.sprite.collide_mask(enemy2, checkpoint):
        enemy2_pos = (random.randint(200, 1720), random.randint(200, 880))

if not thru_cp:
    checkpoint.blit_cp(cp_pos)
if pygame.sprite.collide_mask(enemy0, checkpoint):
    enemy0_pos = (random.randint(200, 1720), random.randint(200, 880))

# draws the coordinate system
pygame.draw.line(screen, (255, 255, 255), (960, 0), (960, 1080), 2)
pygame.draw.line(screen, (255, 255, 255), (0, 540), (1920, 540), 2)

for numbers in range(0, 64):
    pygame.draw.aaline(screen, (255, 255, 255), (numbers * 30, 530), (numbers * 30, 550))

for numbers in range(0, 36):
    pygame.draw.aaline(screen, (255, 255, 255), (950, numbers * 30), (970, numbers * 30))

if box_active:
    inp_rect_color = color_active
else:
    inp_rect_color = color_passive

pygame.draw.rect(screen, inp_rect_color, input_rect, 2)
inp_text_surface = base_font.render(fixed_text_inp_box + user_text, False, (255, 255, 255))
input_rect.w = max(100, inp_text_surface.get_width() + 10)
screen.blit(inp_text_surface, (input_rect.x + 5, input_rect.centery - 5))

launch_button.blit_button((1820, 55), launch_active)

if len(coord_list) > 1:
    try:
        pygame.draw.aalines(screen, (255, 255, 255), False, coord_list, 3)
    except (ValueError, SyntaxError, NameError, TypeError):
        user_text = "Invalid Input"
if draw:
    try:
        coord_list = get_pt_list(user_text)
        prev_coord = coord_list[0]
        for coord in coord_list:
            pygame.draw.aaline(screen, (255, 255, 255), prev_coord, coord)
            pygame.display.flip()
            pygame.time.delay(1)
            prev_coord = coord
    except (ValueError, SyntaxError, NameError, TypeError):
        user_text = "Invalid Input"
    draw = False

if launch:
    try:
        if not thru_enemy:
            y1 = int(coord_list[coord_index][1])
            y2 = int(coord_list[coord_index + 1][1])
            x1 = int(coord_list[coord_index][0])
            x2 = int(coord_list[coord_index + 1][0])
            dy = y1 - y2
            dx = x2 - x1
            angle = math.degrees(math.atan2(dy, dx))
            custom_round(angle, 5)
            angle %= 360
            center = (round(int(coord_list[coord_index][0])), round(int(coord_list[coord_index][1])))
            rocket.blit_rotate_center(screen, center, angle)

            if pygame.sprite.collide_mask(start, rocket):
                thru_start = True
            if pygame.sprite.collide_mask(rocket, end):
                thru_end = True
            if pygame.sprite.collide_mask(checkpoint, rocket):
                thru_cp = True
            if pygame.sprite.collide_mask(rocket, enemy0):
                thru_enemy = True
                print("dead")
            if difficulty > 0:
                if pygame.sprite.collide_mask(rocket, enemy1):
                    thru_enemy = True
                    print("dead")
            if pygame.sprite.collide_mask(rocket, enemy2) and difficulty == 2:
                thru_enemy = True
                print("dead")

            pygame.display.flip()
            rocket.update()

            angle = 0
            coord_index += 20


    except IndexError:
        launch_complete = True
    if thru_enemy:
        launch_complete = True

    if launch_complete:
        coord_index = 0
        launch = False
        launch_active = False
        draw_rocket = False
        launch_complete = False
        if thru_start and thru_end and thru_cp and not thru_enemy:
            win = True
        else:
            thru_start = False
            thru_end = False
            thru_enemy = False
            thru_cp = False
        if win:
            thru_cp = False
            thru_enemy = False
            thru_end = False
            thru_start = False

            end_planet_pos = (1920, random.randint(0, 980))
            start_planet_pos = (0, random.randint(0, 980))
            cp_pos = (random.randint(300, 1620), random.randint(200, 880))
            bg_index = random.randint(0, 3)
            start_exo = end_exo
            end_exo = random.randint(0, 12)
            if start_exo == end_exo:
                if end_exo == 12:
                    end_exo -= 1
                else:
                    end_exo -= 1
            start = Obstacle(exo_list[start_exo], (500, 500))
            end = Obstacle(exo_list[end_exo], (500, 500))
            enemy_index1 = random.randint(0, 3)
            enemy_index2 = random.randint(0, 3)
            enemy_index3 = random.randint(0, 3)
            if enemy_index1 == enemy_index2 == enemy_index3:
                enemy_index2 += 1
            enemy0_pos = (random.randint(200, 1720), random.randint(200, 880))
            enemy1_pos = (random.randint(200, 1720), random.randint(200, 880))
            enemy2_pos = (random.randint(200, 1720), random.randint(200, 880))
            pt_list = []
            coord_list = []
            if difficulty == 0:
                easy_score += 1
                if easy_score > easy_high_score:
                    easy_high_score = easy_score
                    with open('easy_score.dat', 'wb') as file:
                        pickle.dump(easy_high_score, file)

            if difficulty == 1:
                med_score += 1
                if med_score > med_high_score:
                    med_high_score = med_score
                    with open("med_score.dat", "wb") as file:
                        pickle.dump(med_high_score, file)

            if difficulty == 2:
                hard_score += 1
                if hard_score > hard_high_score:
                    hard_high_score = hard_score
                    with open("hard_score.dat", "wb") as file:
                        pickle.dump(hard_high_score, file)

pygame.display.flip()
clock.tick(60)

Link转至比赛录像:https://youtu.be/lkKxZicoOk8

可能的问题是 rect 属性在 blit_rotate_center 方法中被修改。

self.rect = new_rect

由于您使用 rect 属性来计算图像的 top-left 角,这可能会导致反馈循环:

rocket.blit_rotate_center(screen, 
   (int(coord_list[coord_index][0]) - rocket.rect.w / 2,
    int(coord_list[coord_index][1]) - rocket.rect.h / 2), angle)

简化您的代码。使用使用图像中心而不是左上角的旋转方法:

def blit_rotate_center(self, surf, center, rot_angle):
    rotated_image = pygame.transform.rotate(self.image, rot_angle)
    new_rect = rotated_image.get_rect(center=center)
    surf.blit(rotated_image, new_rect)
    self.rect = new_rect

并将对象的中心传递给方法:

center = (round(coord_list[coord_index][0]), round(coord_list[coord_index][1]))
rocket.blit_rotate_center(screen, center, angle)   

另见 and *How do I rotate an image around its center using PyGame?