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?。
我正在开发一款游戏,玩家输入图形 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)
另见