如何知道两个向量之间的角度?
How to know the angle between two vectors?
我正在用 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)
这里用一张图片来说明:
我该如何解决这个问题?
正如一位评论者所说,只有三个点之间或两个相交向量之间的角度可以从这三个点导出。我假设你想要角度,枪和目标(向量 1)和 X-Axis(向量 2)有。这是一个 link 页面,解释了如何计算该角度。 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))
两点夹角的正切定义为delta y / delta x
即 (y2 - y1)/(x2-x1)。这意味着 math.atan2(dy, dx)
给出两点之间的角度 假设 您知道定义 co-ordinates.
的基轴
假设您的枪是轴的 (0, 0) 点,以便以弧度计算角度。获得该角度后,您就可以使用该角度进行剩余的计算。
请注意,由于角度以弧度为单位,因此您需要在代码中使用 math.pi 而不是 180 度。也不需要超过 360 度 (2*math.pi) 的测试。负值 (< 0) 的测试不正确,因为您随后将其强制为 0,这会强制目标在正方向上位于 x 轴上。
计算枪与目标之间角度的代码是
myradians = math.atan2(targetY-gunY, targetX-gunX)
如果要将弧度转换为度数
mydegrees = math.degrees(myradians)
将度数转换为弧度
myradians = math.radians(mydegrees)
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).
Definition Returns the tangent(y,x) in radius.
Syntax
math.atan2(y,x)
Parameters
y,x=numbers
Examples
The return is:
>>> import math
>>> math.atan2(88,34)
1.202100424136847
>>>
专门用于处理 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])
您可以只使用 Pygame 的 Vector2 class which returns the polar coordinates 向量(半径和极角(以度为单位))的 as_polar
方法。
所以只需从第二个点向量中减去第一个点向量,然后调用结果向量的 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)
一般来说,一个向量的角度(x, y)可以通过math.atan2(y, x)
计算出来。向量可以由一条线上的 2 个点 (x1, y1) 和 (x2, y2) 定义。因此直线的角度是math.atan2(y2-y1, x2-x1)
。
请注意 y-axis 需要反转(-y
分别为 y1-y2
),因为 y-axis 通常指向上方,但在 PyGame 坐标系中 y-axis 指向下方。 Pythonmath
模块中角度的单位是Radian, but the unit of the angle in PyGame functions like pygame.transform.rotate()
is 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-axis 并将弧度转换为度数。只需计算向量与 (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()
我使用了以下代码。
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))
我正在用 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)
这里用一张图片来说明:
我该如何解决这个问题?
正如一位评论者所说,只有三个点之间或两个相交向量之间的角度可以从这三个点导出。我假设你想要角度,枪和目标(向量 1)和 X-Axis(向量 2)有。这是一个 link 页面,解释了如何计算该角度。 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))
两点夹角的正切定义为delta y / delta x
即 (y2 - y1)/(x2-x1)。这意味着 math.atan2(dy, dx)
给出两点之间的角度 假设 您知道定义 co-ordinates.
假设您的枪是轴的 (0, 0) 点,以便以弧度计算角度。获得该角度后,您就可以使用该角度进行剩余的计算。
请注意,由于角度以弧度为单位,因此您需要在代码中使用 math.pi 而不是 180 度。也不需要超过 360 度 (2*math.pi) 的测试。负值 (< 0) 的测试不正确,因为您随后将其强制为 0,这会强制目标在正方向上位于 x 轴上。
计算枪与目标之间角度的代码是
myradians = math.atan2(targetY-gunY, targetX-gunX)
如果要将弧度转换为度数
mydegrees = math.degrees(myradians)
将度数转换为弧度
myradians = math.radians(mydegrees)
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).
Definition Returns the tangent(y,x) in radius.
Syntax
math.atan2(y,x)Parameters
y,x=numbersExamples
The return is:>>> import math >>> math.atan2(88,34) 1.202100424136847 >>>
专门用于处理 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])
您可以只使用 Pygame 的 Vector2 class which returns the polar coordinates 向量(半径和极角(以度为单位))的 as_polar
方法。
所以只需从第二个点向量中减去第一个点向量,然后调用结果向量的 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)
一般来说,一个向量的角度(x, y)可以通过math.atan2(y, x)
计算出来。向量可以由一条线上的 2 个点 (x1, y1) 和 (x2, y2) 定义。因此直线的角度是math.atan2(y2-y1, x2-x1)
。
请注意 y-axis 需要反转(-y
分别为 y1-y2
),因为 y-axis 通常指向上方,但在 PyGame 坐标系中 y-axis 指向下方。 Pythonmath
模块中角度的单位是Radian, but the unit of the angle in PyGame functions like pygame.transform.rotate()
is 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-axis 并将弧度转换为度数。只需计算向量与 (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()
我使用了以下代码。
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))