简体   繁体   English

如何知道两个向量之间的角度?

[英]How to know the angle between two vectors?

I am making small game with pygame and I have made a gun that rotates around its center.我正在用 pygame 制作小游戏,并且制作了一把围绕其中心旋转的枪。 My problem is that I want the gun to rotate by itself to the enemy direction, but I couldn't do that because I can't find the angle between the gun and the enemy to make the gun rotate to it I have searched and I found that I have to use the atan2 but I didn't find any working code so I hope someone could help me.我的问题是我想让枪自己旋转到敌人的方向,但我做不到,因为我找不到枪和敌人之间的角度来让枪旋转到我搜索过的方向,我发现我必须使用atan2但我没有找到任何工作代码,所以我希望有人能帮助我。

Here is my code:这是我的代码:

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) 

And here is a picture trying to make it clear:这是一张试图说清楚的图片:

在此处输入图像描述

How do I solve the problem?我该如何解决这个问题?

The tangent of the angle between two points is defined as delta y / delta x That is (y2 - y1)/(x2-x1).两点间夹角的正切定义为delta y / delta x 即(y2 - y1)/(x2-x1)。 This means that math.atan2(dy, dx) give the angle between the two points assuming that you know the base axis that defines the co-ordinates.这意味着math.atan2(dy, dx)给出两点之间的角度,假设您知道定义坐标的基轴。

Your gun is assumed to be the (0, 0) point of the axes in order to calculate the angle in radians.假设您的枪是轴的 (0, 0) 点,以便以弧度计算角度。 Once you have that angle, then you can use the angle for the remainder of your calculations.一旦你有了这个角度,你就可以在剩下的计算中使用这个角度。

Note that since the angle is in radians, you need to use the math.pi instead of 180 degrees within your code.请注意,由于角度以弧度为单位,因此您需要在代码中使用 math.pi 而不是 180 度。 Also your test for more than 360 degrees (2*math.pi) is not needed.也不需要您对超过 360 度 (2*math.pi) 的测试。 The test for negative (< 0) is incorrect as you then force it to 0, which forces the target to be on the x axis in the positive direction.负数 (< 0) 的测试是不正确的,因为您将其强制为 0,这会强制目标在正方向上位于 x 轴上。

Your code to calculate the angle between the gun and the target is thus因此,您计算枪和目标之间角度的代码是

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

If you want to convert radians to degrees如果要将弧度转换为度数

mydegrees = math.degrees(myradians)

To convert from degrees to radians将度数转换为弧度

myradians = math.radians(mydegrees)

Python ATAN2蟒蛇ATAN2

The Python ATAN2 function is one of the Python Math function which is used to returns the angle (in radians) from the X -Axis to the specified point (y, x). Python ATAN2 函数是 Python 数学函数之一,用于返回从 X 轴到指定点 (y, x) 的角度(以弧度为单位)。

math.atan2() 数学.atan2()

Definition Returns the tangent(y,x) in radius.定义返回半径中的切线(y,x)。

Syntax句法
math.atan2(y,x)数学.atan2(y,x)

Parameters参数
y,x=numbers y,x=数字

Examples例子
The return is:回报是:

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

Specifically for working with shapely linestring objects, assuming your object (two points) is of the form (min long, min lat, max long, max lat)专门用于处理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]) 

In general, the angle of a vector (x, y) can be calculated by math.atan2(y, x) .一般来说,向量(x, y)的角度可以通过math.atan2(y, x)来计算。 The vector can be defined by 2 points (x1, y1) and (x2, y2) on a line.向量可以由一条线上的 2 个点(x1, y1)(x2, y2)定义。 Therefore the angle of the line is math.atan2(y2-y1, x2-x1) .因此线的角度是math.atan2(y2-y1, x2-x1) Be aware that the y-axis needs to be reversed ( -y respectively y1-y2 ) because the y-axis is generally pointing up but in the PyGame coordinate system the y-axis is pointing down.请注意,y 轴需要反转(分别为-y y1-y2 ),因为 y 轴通常指向上方,但在 PyGame 坐标系中,y 轴指向下方。 The unit of the angle in the Python math module is Radian , but the unit of the angle in PyGame functions like pygame.transform.rotate() is Degree . Python math模块中的角度单位是Radian ,但 PyGame 函数(如pygame.transform.rotate()中的角度单位是Degree Hence the angle has to be converted from Radians to Degrees by math.degrees :因此必须通过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))

This can be simplified by using the angle_to method of the pygame.math.Vector2 object.这可以通过使用pygame.math.Vector2对象的angle_to方法来简化。 This method computes the angle between 2 vectors in the PyGame coordinate system in degrees.此方法计算 PyGame 坐标系中 2 个向量之间的角度(以度为单位)。 Therefore it is not necessary to reverse the y-axis and convert from radians to degrees.因此,没有必要反转 y 轴并将弧度转换为度数。 Just calculate the angle between the vector and (1, 0) :只需计算向量和(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)

Minimale example:最小示例:

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 can be used to calculate the angle between 2 vectors or lines: angle_to可用于计算 2 个向量或线之间的角度:

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

Minimal example:最小的例子:

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()

I used following code.我使用了以下代码。

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))

As one commenter already said, there is only an angle between three points or between two intersecting vectors, that can be derived from this threee points.正如一位评论者已经说过的,三个点之间或两个相交向量之间只有一个角度,可以从这三个点推导出来。 I assume you want the angle, that the gun and the target (vector 1) and the X-Axis (vector 2) has.我假设您想要枪和目标(矢量 1)和 X 轴(矢量 2)所具有的角度。 Here is a link to a page, that explains how to calculate that angle.这是一个页面的链接,它解释了如何计算该角度。 http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm

Python example: 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))

You can just use the as_polar method of Pygame's Vector2 class which returns the polar coordinates of the vector (radius and polar angle (in degrees)).您可以只使用 Pygame 的Vector2类的as_polar方法,该方法返回向量的极坐标(半径和极角(以度为单位))。

So just subtract the first point vector from the second and call the as_polar method of the resulting vector.所以只需从第二个点向量中减去第一个点向量,然后调用结果向量的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)

For anyone wanting a bit more information on this subject check out omnicalculator's break down of the subject: https://www.omnicalculator.com/math/angle-between-two-vectors对于任何想了解有关此主题的更多信息的人,请查看omnicalculator 对该主题的细分: https ://www.omnicalculator.com/math/angle-between-two-vectors

Extracted relevant information:提取的相关信息:

from math import acos, sqrt, degrees

# returns angle in radians between two points pt1, pt2 where pt1=(x1, y1) and pt2=(x2, y2)
angle = acos((x1 * x2 + y1 * y2)/(sqrt(x1**2 + y1**2) * sqrt(x2**2 + y2**2)))

# convert to degrees
deg_angle = degrees(angle)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM