问题描述
我创建了一个程序来为形状设置动画,我只移动了 x 轴或 y 轴,从来没有同时移动过这两个轴。所以对角移动对我来说是全新的。下面是我的代码:
"""
Author: Victor Xu
Date: January 20th,2021
Description: Animating Shapes with pygame
"""
"""
1. Modify the animation of the red_Box so that when it hits
the left or right side of the window it changes direction. (COMPLETED)
2. Add a green_rect (40x20) Surface that moves in up and down.
It should change its y direction when it hits to top or bottom
of the window. (COMPLETED)
3. Add a blue_circle (24x24) Surface that moves in a diagonal path.
If it hits the top or bottom of the window reverse its
y direction,and if it hits the left or right of the window
reverse its x direction.
"""
import pygame
def main():
'''This function defines the 'mainline logic' for our game.'''
# I - INITIALIZE
pygame.init()
# disPLAY
screen = pygame.display.set_mode((640,480))
pygame.display.set_caption("Crazy Shapes Animation")
# ENTITIES
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((255,255,255)) # white background
# Make a red 25 x 25 Box
red_Box = pygame.Surface((25,25))
red_Box = red_Box.convert()
red_Box.fill((255,0))
# Make a green 40 x 20 rectangle
green_rect = pygame.Surface((40,20))
green_rect = green_rect.convert()
green_rect.fill((0,0))
# Make a blue 24 x 24 circle
blue_circ = pygame.Surface((24,24))
blue_circ = blue_circ.convert()
blue_circ.fill((0,255))
pygame.draw.circle(blue_circ,(0,255),(25,25),24)
# A - ACTION (broken into ALTER steps)
# ASSIGN
clock = pygame.time.Clock()
keepGoing = True
red_Box_x = 0 # Assign starting (x,y)
red_Box_y = 200 # for our red Box
move_red_x = 5
green_rect_x = 300 # Assign starting (x,y)
green_rect_y = 200 # for our green rectangle
move_rect_y = 5
blue_circ_x = 640 # Assign starting (x,y)
blue_circ_y = 0 # for our blue circle
move_circ_x = 5
move_circ_y = 5
# LOOP
while keepGoing:
# TIMER
clock.tick(30)
# EVENT HANDLING
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
# change x coordinate of red Box
red_Box_x += move_red_x
# check boundaries,to bounce off wall
if red_Box_x >= screen.get_width():
red_Box_x = screen.get_width()
move_red_x *= -1
if red_Box_x <= 0:
red_Box_x = 0
move_red_x *= -1
# change y coordinate of green rectangle
green_rect_y += move_rect_y
# check boundaries,to bounce off wall
if green_rect_y >= screen.get_height():
green_rect_y = screen.get_height()
move_rect_y *= -1
if green_rect_y <= 0:
green_rect_y = 0
move_rect_y *= -1
# REFRESH (update window)
screen.blit(background,0))
screen.blit(green_rect,(green_rect_x,green_rect_y)) # blit rectangle at new (x,y) location
screen.blit(red_Box,(red_Box_x,red_Box_y)) # blit Box at new (x,y) location
pygame.display.flip()
# Close the game window
pygame.quit()
# Call the main function
main()
如果你能用我的风格完成它就太好了,这样我就能更好地理解它。非常感谢!
解决方法
我将提供一个更通用的方法。定义对象在途中应访问的位置列表 (circle_pos_list
)。设置起始位置(circle_pos
)、速度(circle_speed
)和列表中下一个目标位置的索引(next_pos_index
)。
circle_pos_list = [(100,100),(200,150),(100,150)]
circle_pos = circle_pos_list[0]
circle_speed = 5
next_pos_index = 1
使用pygame.math.Vector2
计算当前圆到列表中下一个目标位置的距离向量:
circle_dir = pygame.math.Vector2(circle_pos_list[next_pos_index]) - circle_pos
如果到目标的距离小于圆的速度,则踩到目标并将目标位置索引改为下一个目标:
if circle_dir.length() < circle_speed:
circle_pos = circle_pos_list[next_pos_index]
next_pos_index = (next_pos_index + 1) % len(circle_pos_list)
否则,沿着向量一步到下一个目的地:
circle_dir.scale_to_length(circle_speed)
new_pos = pygame.math.Vector2(circle_pos) + circle_dir
circle_pos = (new_pos.x,new_pos.y)
代码中的更改:
def main():
# [...]
blue_circ = pygame.Surface((24,24))
blue_circ.set_colorkey((0,0))
pygame.draw.circle(blue_circ,(0,255),(12,12),12)
# [...]
circle_pos_list = [(100,150)]
circle_pos = circle_pos_list[0]
circle_speed = 5
next_pos_index = 1
# LOOP
while keepGoing:
# [...]
circle_dir = pygame.math.Vector2(circle_pos_list[next_pos_index]) - circle_pos
if circle_dir.length() < circle_speed:
circle_pos = circle_pos_list[next_pos_index]
next_pos_index = (next_pos_index + 1) % len(circle_pos_list)
else:
circle_dir.scale_to_length(circle_speed)
new_pos = pygame.math.Vector2(circle_pos) + circle_dir
circle_pos = (new_pos.x,new_pos.y)
# [...]
screen.blit(blue_circ,(round(circle_pos[0]),round(circle_pos[1])))
# [...]