¿Cómo saber el ángulo entre dos vectores?

Resuelto Luca-Fly asked hace 7 años • 0 respuestas

Estoy haciendo caza menor con pygame y he hecho una pistola que gira alrededor de su centro. Mi problema es que quiero que el arma gire por sí sola hacia la dirección del enemigo, pero no pude hacerlo porque no puedo encontrar el ángulo entre el arma y el enemigo para hacer que el arma gire hacia él. He buscado y Descubrí que tengo que usar atan2pero no encontré ningún código que funcione, así que espero que alguien pueda ayudarme.

Aquí está mi código:

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) 

Y aquí una imagen que intenta dejarlo claro:

ingrese la descripción de la imagen aquí

¿Cómo soluciono el problema?

Luca-Fly avatar Feb 16 '17 02:02 Luca-Fly
Aceptado

La tangente del ángulo entre dos puntos se define como delta y / delta x Es decir (y2 - y1)/(x2-x1). Esto significa que math.atan2(dy, dx)da el ángulo entre los dos puntos suponiendo que conoces el eje base que define las coordenadas.

Se supone que su arma es el punto (0, 0) de los ejes para calcular el ángulo en radianes. Una vez que tenga ese ángulo, podrá usarlo para el resto de sus cálculos.

Tenga en cuenta que, dado que el ángulo está en radianes, debe usar math.pi en lugar de 180 grados dentro de su código. Además, no es necesaria su prueba de más de 360 ​​grados (2*math.pi). La prueba de negativo (< 0) es incorrecta ya que luego la fuerza a 0, lo que obliga al objetivo a estar en el eje x en la dirección positiva.

Su código para calcular el ángulo entre el arma y el objetivo es así

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

Si quieres convertir radianes a grados

mydegrees = math.degrees(myradians)

Para convertir de grados a radianes

myradians = math.radians(mydegrees)

Pitón ATAN2

La función Python ATAN2 es una de las funciones matemáticas de Python que se utiliza para devolver el ángulo (en radianes) desde el eje X hasta el punto especificado (y, x).

matemáticas.atan2()

Definición Devuelve la tangente(y,x) en radio.

Sintaxis
math.atan2(y,x)

Parámetros
y,x=números

Ejemplos
La devolución es:

>>> import math  
>>> math.atan2(88,34)  
1.202100424136847  
>>>
sabbahillel avatar Feb 15 '2017 19:02 sabbahillel

En general, el ángulo de un vector (x, y) se puede calcular mediante math.atan2(y, x). El vector se puede definir por 2 puntos (x1, y1) y (x2, y2) en una recta. Por tanto el ángulo de la recta es math.atan2(y2-y1, x2-x1). Tenga en cuenta que el eje y debe invertirse ( -yrespectivamente y1-y2) porque el eje y generalmente apunta hacia arriba, pero en el sistema de coordenadas PyGame el eje y apunta hacia abajo. La unidad del ángulo en el mathmódulo Python es Radian , pero la unidad del ángulo en PyGame funciona pygame.transform.rotate()como Grado . Por lo tanto, el ángulo debe convertirse de radianes a grados mediante 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))

Esto se puede simplificar utilizando el angle_tométodo del pygame.math.Vector2objeto. Este método calcula el ángulo entre 2 vectores en el sistema de coordenadas PyGame en grados. Por lo tanto, no es necesario invertir el eje y y convertir de radianes a grados. Simplemente calcule el ángulo entre el vector 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)

Ejemplo mínimo:

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_tose puede utilizar para calcular el ángulo entre 2 vectores o líneas:

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

Ejemplo mínimo:

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()
Rabbid76 avatar Oct 27 '2020 21:10 Rabbid76

Específicamente para trabajar con shapely linestringobjetos, asumiendo que su objeto (dos puntos) tiene la forma(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]) 
Chidi avatar Aug 01 '2018 14:08 Chidi

Usé el siguiente código.

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))
NEERAJ SWARNKAR avatar Nov 22 '2021 18:11 NEERAJ SWARNKAR