Pygame: 如何通过位图和旋转图像来连接屏幕上的两点?
Pygame: How do I blit and rotate an image to connect two points on the screen?
这是一个测试程序。我从两个随机点和连接它们的线开始。现在,我想拍摄一张给定的图像(x、y 尺寸为 79 x 1080)并将其 blit 到引导线的顶部。我知道 arctan
会给我笛卡尔网格上各点之间的角度,但是因为 y 在屏幕 (x,y) 的后面,所以我必须反转一些值。我对否定步骤感到困惑。
如果您 运行 重复此操作,您会看到图像始终与直线平行,有时在顶部,但并不始终如一。
import math
import pygame
import random
pygame.init()
screen = pygame.display.set_mode((600,600))
#target = (126, 270)
#start = (234, 54)
target = (random.randrange(600), random.randrange(600))
start = (random.randrange(600), random.randrange(600))
BLACK = (0,0,0)
BLUE = (0,0,128)
GREEN = (0,128,0)
pygame.draw.circle(screen, GREEN, start, 15)
pygame.draw.circle(screen, BLUE, target, 15)
pygame.draw.line(screen, BLUE, start, target, 5)
route = pygame.Surface((79,1080))
route.set_colorkey(BLACK)
BMP = pygame.image.load('art/trade_route00.png').convert()
(bx, by, bwidth, bheight) = route.get_rect()
route.blit(BMP, (0,0), area=route.get_rect())
# get distance within screen in pixels
dist = math.sqrt((start[0] - target[0])**2 + (start[1] - target[1])**2)
# scale to fit: use distance between points, and make width extra skinny.
route = pygame.transform.scale(route, (int(bwidth * dist/bwidth * 0.05), int( bheight * dist/bheight)))
# and rotate... (invert, as negative is for clockwise)
angle = math.degrees(math.atan2(-1*(target[1]-start[1]), target[0]-start[0]))
route = pygame.transform.rotate(route, angle + 90 )
position = route.get_rect()
HERE = (abs(target[0] - position[2]), target[1]) # - position[3]/2)
print(HERE)
screen.blit(route, HERE)
pygame.display.update()
print(start, target, dist, angle, position)
主要问题
错误不是由于您似乎认为旋转时的逆 y 坐标(顶部为 0,底部为最大值)引起的。那部分是正确的。错误在这里:
HERE = (abs(target[0] - position[2]), target[1]) # - position[3]/2)
HERE
必须是矩形左上角的坐标,由蓝线连接的绿点和蓝点。在这些坐标处,您需要在重新缩放后放置 Surface route
。
您可以通过以下方式获得该顶点:
HERE = (min(start[0], target[0]), min(start[1], target[1]))
这应该可以解决问题,您的彩色点应该位于蓝线上。
边注
您可能希望修复的另一件事是 route
:
的缩放参数
route = pygame.transform.scale(route, (int(bwidth * dist/bwidth * 0.05), int( bheight * dist/bheight)))
如果我的猜测是正确的,并且您想在重新缩放后的 route
中保留原始 widht/height 比率(因为您的原始图像不是正方形),这应该是:
route = pygame.transform.scale(route, (int(dist* bwidth/bheight), int(dist)))
假设您希望将高度(原始尺寸中较大的尺寸)缩放至 dist
。所以你可能不需要 0.05
,或者你可以使用不同的收缩参数(可能 0.05 会收缩太多)。
这是一个测试程序。我从两个随机点和连接它们的线开始。现在,我想拍摄一张给定的图像(x、y 尺寸为 79 x 1080)并将其 blit 到引导线的顶部。我知道 arctan
会给我笛卡尔网格上各点之间的角度,但是因为 y 在屏幕 (x,y) 的后面,所以我必须反转一些值。我对否定步骤感到困惑。
如果您 运行 重复此操作,您会看到图像始终与直线平行,有时在顶部,但并不始终如一。
import math
import pygame
import random
pygame.init()
screen = pygame.display.set_mode((600,600))
#target = (126, 270)
#start = (234, 54)
target = (random.randrange(600), random.randrange(600))
start = (random.randrange(600), random.randrange(600))
BLACK = (0,0,0)
BLUE = (0,0,128)
GREEN = (0,128,0)
pygame.draw.circle(screen, GREEN, start, 15)
pygame.draw.circle(screen, BLUE, target, 15)
pygame.draw.line(screen, BLUE, start, target, 5)
route = pygame.Surface((79,1080))
route.set_colorkey(BLACK)
BMP = pygame.image.load('art/trade_route00.png').convert()
(bx, by, bwidth, bheight) = route.get_rect()
route.blit(BMP, (0,0), area=route.get_rect())
# get distance within screen in pixels
dist = math.sqrt((start[0] - target[0])**2 + (start[1] - target[1])**2)
# scale to fit: use distance between points, and make width extra skinny.
route = pygame.transform.scale(route, (int(bwidth * dist/bwidth * 0.05), int( bheight * dist/bheight)))
# and rotate... (invert, as negative is for clockwise)
angle = math.degrees(math.atan2(-1*(target[1]-start[1]), target[0]-start[0]))
route = pygame.transform.rotate(route, angle + 90 )
position = route.get_rect()
HERE = (abs(target[0] - position[2]), target[1]) # - position[3]/2)
print(HERE)
screen.blit(route, HERE)
pygame.display.update()
print(start, target, dist, angle, position)
主要问题
错误不是由于您似乎认为旋转时的逆 y 坐标(顶部为 0,底部为最大值)引起的。那部分是正确的。错误在这里:
HERE = (abs(target[0] - position[2]), target[1]) # - position[3]/2)
HERE
必须是矩形左上角的坐标,由蓝线连接的绿点和蓝点。在这些坐标处,您需要在重新缩放后放置 Surface route
。
您可以通过以下方式获得该顶点:
HERE = (min(start[0], target[0]), min(start[1], target[1]))
这应该可以解决问题,您的彩色点应该位于蓝线上。
边注
您可能希望修复的另一件事是 route
:
route = pygame.transform.scale(route, (int(bwidth * dist/bwidth * 0.05), int( bheight * dist/bheight)))
如果我的猜测是正确的,并且您想在重新缩放后的 route
中保留原始 widht/height 比率(因为您的原始图像不是正方形),这应该是:
route = pygame.transform.scale(route, (int(dist* bwidth/bheight), int(dist)))
假设您希望将高度(原始尺寸中较大的尺寸)缩放至 dist
。所以你可能不需要 0.05
,或者你可以使用不同的收缩参数(可能 0.05 会收缩太多)。