You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何确定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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 04:10:58