如何确定PyGame中拖拽小球时矢量箭头的三点坐标
解决Pygame拖拽小球时矢量箭头绘制问题
我需要在拖拽小球对象时绘制矢量,目前已完成线段的绘制,剩余任务是绘制指示矢量方向的箭头,但无法确定能让箭头正确指向的三点坐标。以下是当前使用的PyGame代码:
try: import pygame,ctypes import pygame.draw as dr from math import * pygame.init() def interaction(xM,yM,x,y): if x<=xM and xM<=x+(10*sqrt(12)) and xM!=x: if y<=yM and yM<=y+(10*sqrt(2)) and yM!=y: return True else:return False else:return False def angle(x,y): if x>0:a=80 else:a=-80 return degrees(acos((x*a)/(abs(a)*vec_magnitude(x,y)))) def vec_magnitude(x,y): return abs(sqrt((x**2)+(y**2))) length=1380 width=720 display=pygame.display.set_mode((length,width)) #mau white=(255,255,255) black=(0,0,0) green=(0, 153, 51) red=(204, 0, 0) blue=(0, 51, 204) yellow=(255, 204, 0) xO,yO=80,620 x,y=xO,yO-10 running=True acceleration=bool(False) while running: display.fill(black) #vat nem da_ball=dr.circle(display,green,(x,y),10) pos=pygame.mouse.get_pos() #print(pos) for event in pygame.event.get(): if event.type==pygame.QUIT:running=False #gia toc bong if event.type==pygame.MOUSEBUTTONDOWN and interaction(pos[0],pos[1],x-(5*sqrt(2)),y-(5*sqrt(2))): acceleration=True elif event.type==pygame.MOUSEBUTTONUP:acceleration=False if acceleration: dr.line(display,yellow,(x,y),(pos[0],pos[1]),3) alp=angle(pos[0]-x,pos[1]-y) dx=8*sin(alp) dy=8*cos(alp) #Draw Vector Here if pos[0]>x and pos[1]<=y: dr.polygon(display,yellow,((pos[0]-dx,pos[1]-dy),(pos[0]+dx,pos[1]+dy),(pos[0]+dy,pos[1]-dx))) pygame.display.update pygame.quit() except Exception as e: ctypes.windll.user32.MessageBoxW(0,str(e),"ErrorBox",16)
解决方案
核心是通过计算矢量的单位方向,结合固定偏转角度生成箭头的两个侧点,无需分象限判断即可让箭头正确指向鼠标方向。
修改后的完整代码
try: import pygame, ctypes import pygame.draw as dr from math import * pygame.init() def interaction(xM, yM, x, y): # 简化碰撞检测:判断鼠标是否在小球范围内 distance = sqrt((xM - x)**2 + (yM - y)**2) return distance <= 10 def vec_magnitude(x, y): return sqrt(x**2 + y**2) length = 1380 width = 720 display = pygame.display.set_mode((length, width)) # 颜色定义 white = (255, 255, 255) black = (0, 0, 0) green = (0, 153, 51) red = (204, 0, 0) blue = (0, 51, 204) yellow = (255, 204, 0) xO, yO = 80, 620 x, y = xO, yO - 10 running = True acceleration = False # 箭头参数:长度和与主线段的夹角 arrow_length = 12 arrow_angle = radians(30) while running: display.fill(black) # 绘制小球 dr.circle(display, green, (x, y), 10) pos = pygame.mouse.get_pos() for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # 检测鼠标按下选中小球 if event.type == pygame.MOUSEBUTTONDOWN: if interaction(pos[0], pos[1], x, y): acceleration = True elif event.type == pygame.MOUSEBUTTONUP: acceleration = False if acceleration: start_pos = (x, y) end_pos = pos # 绘制主矢量线段 dr.line(display, yellow, start_pos, end_pos, 3) # 计算矢量方向的差值和模长 dx = end_pos[0] - start_pos[0] dy = end_pos[1] - start_pos[1] mag = vec_magnitude(dx, dy) if mag == 0: continue # 避免除以零错误 # 计算单位矢量(方向归一化) ux = dx / mag uy = dy / mag # 计算箭头两个侧点的坐标 # 左侧点:沿矢量方向反向偏移,同时向左偏转arrow_angle side1_x = end_pos[0] - arrow_length * (ux * cos(arrow_angle) + uy * sin(arrow_angle)) side1_y = end_pos[1] - arrow_length * (-ux * sin(arrow_angle) + uy * cos(arrow_angle)) # 右侧点:沿矢量方向反向偏移,同时向右偏转arrow_angle side2_x = end_pos[0] - arrow_length * (ux * cos(arrow_angle) - uy * sin(arrow_angle)) side2_y = end_pos[1] - arrow_length * (ux * sin(arrow_angle) + uy * cos(arrow_angle)) # 绘制箭头多边形(终点+两个侧点) dr.polygon(display, yellow, (end_pos, (side1_x, side1_y), (side2_x, side2_y))) pygame.display.update() # 修复原代码的调用错误 pygame.quit() except Exception as e: ctypes.windll.user32.MessageBoxW(0, str(e), "ErrorBox", 16)
关键修改点
- 碰撞检测优化:原
interaction函数逻辑冗余且不准确,改为通过距离判断鼠标是否在小球范围内,更简洁可靠。 - 移除错误角度计算:原
angle函数逻辑混乱,改用单位矢量和三角函数直接计算箭头侧点,适配所有方向。 - 通用箭头生成:通过单位矢量和固定偏转角度,生成箭头的两个侧点,无论鼠标在哪个象限,箭头都能正确指向。
- 修复画面刷新:原代码
pygame.display.update缺少括号,导致画面无法更新,现已修正。
内容的提问来源于stack exchange,提问作者Hồ Quang Vinh
相关产品推荐
相关产品推荐

