【问题标题】:How to know the angle between two vectors?如何知道两个向量之间的角度?
【发布时间】:2022-01-31 04:16:15
【问题描述】:

我正在用 pygame 制作小游戏,并且我制作了一把围绕其中心旋转的枪。 我的问题是我想让枪自己旋转到敌人的方向,但我做不到,因为我找不到枪和敌人之间的角度让枪旋转到它 我已经搜索过,我发现我必须使用atan2,但我没有找到任何有效的代码,所以我希望有人能帮助我。

这是我的代码:

import pygame
from pygame.locals import*
pygame.init()
height=650
width=650
screen=pygame.display.set_mode((height,width))
clock=pygame.time.Clock()
gun=pygame.image.load("m2.png").convert_alpha() 
gun=pygame.transform.smoothscale(gun,(200,200)).convert_alpha()
angle=0
angle_change=0
RED=(255,0,0)
x=525
y=155
while True :
    screen.fill((150,150,150))
    for event in pygame.event.get():
        if event.type==QUIT:
            pygame.quit()
            quit()
        if event.type==KEYDOWN:
            if event.key==K_a:
                angle_change=+1
            if event.key==K_d:
                angle_change=-1
        elif event.type==KEYUP:
            angle_change=0
    angle+=angle_change
    if angle>360:
        angle=0
    if angle<0:
        angle=360
    pygame.draw.rect(screen,RED,(x,y,64,64))
    position = (height/2,width/2)
    gun_rotate=pygame.transform.rotate(gun,angle) 
    rotate_rect = gun_rotate.get_rect()
    rotate_rect.center = position
    screen.blit(gun_rotate, rotate_rect)
    pygame.display.update()
    clock.tick(60) 

这是一张试图说明问题的图片:

我该如何解决这个问题?

【问题讨论】:

  • 你可能想先在纸上画出数学,然后在代码中实现它。
  • 两点之间没有夹角...三个点之间只有夹角...
  • 两个向量之间的夹角是angle = acos(v1•v2),其中 表示“点积”?听起来这里的两个向量将由射手的当前位置和枪当前指向的方向,加上当前位置和敌人的位置来定义。
  • @martineau 由于枪和目标是相对于隐式 x、y 轴定义的,因此将使用 tangent = (y2-y1)/(x2-x1)。这允许使用 atan2。
  • 回答他想问的,而不是他问的。在这种情况下,我假设他想要坐标系下一个 90 度分割的角度。

标签: python math pygame angle


【解决方案1】:

两点间夹角的正切定义为delta y / delta x 即 (y2 - y1)/(x2-x1)。这意味着math.atan2(dy, dx) 给出了两点之间的角度假设您知道定义坐标的基轴。

假设您的枪是轴的 (0, 0) 点,以便以弧度计算角度。一旦你有了这个角度,你就可以在剩下的计算中使用这个角度。

请注意,由于角度以弧度为单位,因此您需要在代码中使用 math.pi 而不是 180 度。也不需要您对超过 360 度 (2*math.pi) 的测试。负数 (

因此,您计算枪与目标之间角度的代码是

myradians = math.atan2(targetY-gunY, targetX-gunX)

如果要将弧度转换为度数

mydegrees = math.degrees(myradians)

将度数转换为弧度

myradians = math.radians(mydegrees)

Python ATAN2

Python ATAN2 函数是 Python 数学函数之一,它是 用于返回从 X 轴到 指定点 (y, x)。

math.atan2()

定义返回以半径为单位的切线(y,x)。

语法
数学.atan2(y,x)

参数
y,x=数字

示例
返回是:

>>> import math  
>>> math.atan2(88,34)  
1.202100424136847  
>>>

【讨论】:

  • 非常感谢先生,这对我的代码非常有用,有助于更多地了解角度
  • @مهند عبد الجليل 谢谢,如果您愿意,可以通过检查答案一侧的复选标记来接受它。
  • 完成先生 :) 抱歉,当我在这里得到答案时,我不知道我必须这样做
  • @مهند عبد الجليل 您不必必须如果您愿意,可以标记已接受的答案。
  • 供参考,这是 math.atan2() 的官方和最新文档:docs.python.org/3/library/math.html#math.atan2
【解决方案2】:

专门用于处理shapely linestring 对象,假设您的对象(两点)的形式为(min long, min lat, max long, max lat)

from math import atan2,degrees
line = #Your-LineString-Object
lineList = list(line.coords)

def AngleBtw2Points(pointA, pointB):
  changeInX = pointB[0] - pointA[0]
  changeInY = pointB[1] - pointA[1]
  return degrees(atan2(changeInY,changeInX)) #remove degrees if you want your answer in radians

AngleBtw2Points(lineList[0],lineList[1]) 

【讨论】:

    【解决方案3】:

    一般来说,一个向量(x, y)的角度可以通过math.atan2(y, x)来计算。向量可以由直线上的 2 个点 (x1, y1)(x2, y2) 定义。因此线的角度是math.atan2(y2-y1, x2-x1)。 请注意,y 轴需要反转(-y 分别为 y1-y2),因为 y 轴通常指向上方,但在 PyGame 坐标系中,y 轴指向下方。 Python math 模块中的角度单位为Radian,但在pygame.transform.rotate() 等PyGame 函数中的角度单位为Degree。因此角度必须通过math.degrees从弧度转换为度数:

    import math
    
    def angle_of_vector(x, y):
        return math.degrees(math.atan2(-y, x))
    
    def angle_of_line(x1, y1, x2, y2):
        return math.degrees(math.atan2(-(y2-y1), x2-x1))
    

    这可以通过使用pygame.math.Vector2 对象的angle_to 方法来简化。此方法计算 PyGame 坐标系中 2 个向量之间的角度(以度为单位)。因此,没有必要反转 y 轴并将弧度转换为度数。只需计算向量与(1, 0)的夹角:

    def angle_of_vector(x, y):
        return pygame.math.Vector2(x, y).angle_to((1, 0))
    
    def angle_of_line(x1, y1, x2, y2):
        return angle_of_vector(x2-x1, y2-y1)
    

    小例子:

    import pygame
    import math
    
    def angle_of_vector(x, y):
        #return math.degrees(math.atan2(-y, x))            # 1: with math.atan
        return pygame.math.Vector2(x, y).angle_to((1, 0))  # 2: with pygame.math.Vector2.angle_to
        
    def angle_of_line(x1, y1, x2, y2):
        #return math.degrees(math.atan2(-y1-y2, x2-x1))    # 1: math.atan
        return angle_of_vector(x2-x1, y2-y1)               # 2: pygame.math.Vector2.angle_to
        
    pygame.init()
    window = pygame.display.set_mode((400, 400))
    clock = pygame.time.Clock()
    font = pygame.font.SysFont(None, 50)
    
    angle = 0
    radius = 150
    vec = (radius, 0)
    
    run = True
    while run:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
    
        cpt = window.get_rect().center
        pt = cpt[0] + vec[0], cpt[1] + vec[1]
        angle = angle_of_vector(*vec)
    
        window.fill((255, 255, 255))
        pygame.draw.circle(window, (0, 0, 0), cpt, radius, 1)
        pygame.draw.line(window, (0, 255, 0), cpt, (cpt[0] + radius, cpt[1]), 3)
        pygame.draw.line(window, (255, 0, 0), cpt, pt, 3)
        text_surf = font.render(str(round(angle/5)*5) + "°", True, (255, 0, 0))
        text_surf.set_alpha(127)
        window.blit(text_surf, text_surf.get_rect(bottomleft = (cpt[0]+20, cpt[1]-20)))
        pygame.display.flip()
    
        angle = (angle + 1) % 360
        vec = radius * math.cos(angle*math.pi/180), radius * -math.sin(angle*math.pi/180)
    
    pygame.quit()
    exit()
    

    angle_to可用于计算2个向量或直线之间的夹角:

    def angle_between_vectors(x1, y1, x2, y2):
        return pygame.math.Vector2(x1, y1).angle_to((x2, y2))
    

    小例子:

    import pygame
    import math
    
    def angle_between_vectors(x1, y1, x2, y2):
        return pygame.math.Vector2(x1, y1).angle_to((x2, y2))
    
    def angle_of_vector(x, y):
        return pygame.math.Vector2(x, y).angle_to((1, 0))    
        
    pygame.init()
    window = pygame.display.set_mode((400, 400))
    clock = pygame.time.Clock()
    font = pygame.font.SysFont(None, 50)
    
    angle = 0
    radius = 150
    vec1 = (radius, 0)
    vec2 = (radius, 0)
    
    run = True
    while run:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
    
        cpt = window.get_rect().center
        pt1 = cpt[0] + vec1[0], cpt[1] + vec1[1]
        pt2 = cpt[0] + vec2[0], cpt[1] + vec2[1]
        angle = angle_between_vectors(*vec2, *vec1)
    
        window.fill((255, 255, 255))
        pygame.draw.circle(window, (0, 0, 0), cpt, radius, 1)
        pygame.draw.line(window, (0, 255, 0), cpt, pt1, 3)
        pygame.draw.line(window, (255, 0, 0), cpt, pt2, 3)
        text_surf = font.render(str(round(angle/5)*5) + "°", True, (255, 0, 0))
        text_surf.set_alpha(127)
        window.blit(text_surf, text_surf.get_rect(bottomleft = (cpt[0]+20, cpt[1]-20)))
        pygame.display.flip()
    
        angle1 = (angle_of_vector(*vec1) + 1/3) % 360
        vec1 = radius * math.cos(angle1*math.pi/180), radius * -math.sin(angle1*math.pi/180)
        angle2 = (angle_of_vector(*vec2) + 1) % 360
        vec2 = radius * math.cos(angle2*math.pi/180), radius * -math.sin(angle2*math.pi/180)
    
    pygame.quit()
    exit()
    

    【讨论】:

      【解决方案4】:

      我使用了以下代码。

      import math
      
      def get_angle(x1,y1,x2,y2):
          myradians = math.atan2(y1-y2, x1-x2)
          mydegrees = math.degrees(myradians)
          return mydegrees
      
      # it should return -90 degree
      print(get_angle(0,0,0,100))
      

      【讨论】:

        【解决方案5】:

        正如一位评论者已经说过的,三个点之间或两个相交向量之间只有一个角度,可以从这三个点推导出来。我假设您想要枪和目标(矢量 1)和 X 轴(矢量 2)所具有的角度。这是一个页面的链接,它解释了如何计算该角度。 http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm

        Python 示例:

        import math
        
        def angle(vector1, vector2):
            length1 = math.sqrt(vector1[0] * vector1[0] + vector1[1] * vector1[1])
            length2 = math.sqrt(vector2[0] * vector2[0] + vector2[1] * vector2[1])
            return math.acos((vector1[0] * vector2[0] + vector1[1] * vector2[1])/ (length1 * length2))
        
        vector1 = [targetX - gunX, targetY - gunY] # Vector of aiming of the gun at the target
        vector2 = [1,0] #vector of X-axis
        print(angle(vector1, vector2))
        

        【讨论】:

        • 由于枪和目标是相对于隐式 x、y 轴定义的,因此将使用 tangent = (y2-y1)/(x2-x1)。这允许使用 atan2。您不需要计算(隐式)轴向量。
        • 没错,atan2 是一个可能的捷径。出于解释的原因,我展示了一般数学公式。
        • 在任何一种情况下,您都不需要使用向量 2,因为向量 1 允许您进行所需的计算。
        【解决方案6】:

        您可以只使用 Pygame 的 Vector2 类的 as_polar 方法,该方法返回矢量的 polar coordinates(半径和极角(以度为单位))。

        所以只需从第二个点向量中减去第一个点向量,然后调用结果向量的as_polar 方法。

        import pygame as pg
        from pygame.math import Vector2
        
        
        pg.init()
        screen = pg.display.set_mode((640, 480))
        clock = pg.time.Clock()
        BG_COLOR = pg.Color('gray12')
        
        point = Vector2(320, 240)
        mouse_pos = Vector2(0, 0)
        radius, angle = (mouse_pos - point).as_polar()
        
        done = False
        while not done:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    done = True
                elif event.type == pg.MOUSEMOTION:
                    mouse_pos = event.pos
                    radius, angle = (mouse_pos - point).as_polar()
        
            screen.fill(BG_COLOR)
            pg.draw.line(screen, (0, 100, 255), point, mouse_pos)
            pg.display.set_caption(f'radius: {radius:.2f} angle: {angle:.2f}')
            pg.display.flip()
            clock.tick(60)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-03-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多