Làm thế nào tôi có thể tính toán góc và hướng rẽ thích hợp giữa hai vectơ 2D?


26

Tôi đang làm việc trên một số chuyển động AI, nơi không có chướng ngại vật và chuyển động bị giới hạn trong mặt phẳng XY. Tôi đang tính hai vectơ, v , hướng đối diện của tàu 1 và w , vectơ chỉ từ vị trí của tàu 1 đến tàu 2.

Sau đó tôi tính toán góc giữa hai vectơ này bằng công thức

arccos((v · w) / (|v| · |w|))

Vấn đề tôi gặp phải là arccoschỉ trả về các giá trị trong khoảng từ 0 ° đến 180 °. Điều này khiến tôi không thể xác định liệu tôi nên rẽ trái hay phải để đối mặt với con tàu khác.

Có cách nào tốt hơn để làm điều này?


1
Nếu bạn đang sử dụng Unity, hãy kiểm tra Mathf.DeltaAngle().
Russell Borogove

Câu trả lời:


22

Sử dụng sản phẩm chéo 2d nhanh hơn nhiều. Không có chức năng trig tốn kém liên quan.

b2Vec2 target( ... );
b2Vec2 heading( ... );

float cross = b2Cross( target, heading );

if( cross == -0.0f )
   // turn around

if( cross == 0.0f )
  // already traveling the right direction

if( cross < 0.0f)
  // turn left

if( cross > 0.0f)
  // turn right

Nếu bạn vẫn cần các góc thực tế tôi khuyên bạn nên sử dụng atan2. atan2sẽ cung cấp cho bạn góc tuyệt đối của bất kỳ vector. Để có được góc tương đối giữa bất kỳ vectơ nào, hãy tính góc tuyệt đối của chúng và sử dụng phép trừ đơn giản.

b2Vec2 A(...);
b2Vec2 B(...);

float angle_A = std::atan2(A.y,A.x);
float angle_B = B.GetAngle(); // Box2D already figured this out for you.

float angle_from_A_to_B = angle_B-angle_A;
float angle_from_B_to_A = angle_A-angle_B;

1
Sau khi đọc câu trả lời của @ Tetrad, tôi cho rằng bạn có thể kết hợp một sản phẩm chéo và một arccos. Bằng cách này, bạn sẽ chỉ sử dụng một chức năng trig, nhưng vẫn có góc thực tế. Tuy nhiên, tôi khuyên bạn nên chống lại tối ưu hóa này cho đến khi bạn chắc chắn rằng theo dõi góc AI của bạn đang tạo ra tác động đáng chú ý đến hiệu suất trò chơi của bạn.
deft_code

2
Có, khi chuyển đổi giữa các vectơ và góc, atan2 () chắc chắn là bạn của bạn.
bluescrn

1
Cảm ơn! Tôi thấy rằng tôi thực sự không cần góc, việc lấy sản phẩm chéo 2D là đủ đơn giản cho nhu cầu của tôi.
Lỗi 454

2
Ngoài ra kiểm tra if( cross == -0.0f )vs của bạn if( cross == 0.0f )trông cực kỳ mong manh.
bobobobo

1
@bobobobo, với một công cụ vật lý, nó có thể không phải là một lựa chọn để chỉ chọn một hướng và di chuyển. Biến ảo có thể khiến động cơ vật lý hoảng loạn. Hơn nữa xoay kỳ diệu trông cũng khủng khiếp cho hoạt hình. Vì vậy, có, bạn có thể giải quyết điều này mà không cần khái niệm trái hay phải, nhưng một giải pháp được đánh bóng thường cần những thứ này.
deft_code

10

Sử dụng arcsin của sản phẩm chéo 2D (tức là thành phần z của vectơ sản phẩm chéo). Điều đó sẽ cung cấp cho bạn từ 90 đến 90, điều này sẽ cho bạn biết nên đi sang trái hay phải.

Cẩn thận vì A chéo B không giống với B chéo A.

Một chiến lược khác (nhưng có lẽ không đơn giản như trước) là tính toán "tiêu đề" của hai vectơ bằng atan2 và sau đó tìm hiểu xem A chỉ vào X độ cần phải đi sang trái hay phải để đi đến B chỉ vào độ y.


Cảm ơn bạn đã phản hồi. Để rõ ràng cho các trình duyệt trong tương lai, lấy sin nghịch đảo về độ lớn của sản phẩm chéo 2d sẽ mang lại giá trị trong khoảng từ 0 đến 90. Lấy sin của thành phần z của sản phẩm chéo 2d mang lại kết quả mong muốn.
Lỗi 454

@Error 454, bạn hoàn toàn đúng, đã sửa bài đăng của tôi.
Tetrad

1

Sử dụng các vectơ để chuyển hướng tàu. Đây là cách "hành vi lái" hoạt động - bạn không bao giờ cần tính toán góc, chỉ cần sử dụng các vectơ bạn có. Đây là tính toán rẻ hơn nhiều.

Vectơ w(vectơ từ Tàu 1 đến Tàu 2) là tất cả thông tin bạn cần. Sửa đổi vectơ vận tốc của tàu 1 hoặc vectơ gia tốc của tàu 1 (hoặc thậm chí là vectơ tiêu đề trực tiếp) bằng cách sử dụng phiên bản có trọng số của w.

nhập mô tả hình ảnh ở đây

Tầm quan trọng của việc tàu 1 đi được bao xa (mức độ v không khớp với w) có thể được tìm thấy bằng cách sử dụng ( 1 - dot(v,w))

  • ( dot(v,w)được tối đa hóa khi vwxếp hàng chính xác)
  • ( 1 - dot(v,w)) cho 0 khi vwđược xếp hoàn toàn, được cung cấp vwđược chuẩn hóa)

0

Có một cách đơn giản để tìm góc tuyệt đối của một vectơ thông qua hình học bình thường.

ví dụ vectơ V = 2i - 3j;

giá trị tuyệt đối của hệ số x = 2;

giá trị tuyệt đối của hệ số y = 3;

góc = atan (2/3); [góc sẽ nằm trong khoảng từ 0 đến 90]

Dựa trên góc phần tư sẽ được thay đổi.

if (x hệ số <0 và hệ số y> 0) thì angle = 180-angle;

if (x hệ số <0 và hệ số y <0) thì angle = 180 + angle;

if (x hệ số> 0 và hệ số y <0) thì angle = 360-angle;

if (hệ số x> 0 và hệ số y> 0) thì angle = angle;

sau khi tìm góc của vectơ thứ nhất và thứ hai, chỉ cần trừ góc vectơ thứ nhất khỏi vectơ thứ hai. Sau đó, bạn sẽ có được góc tuyệt đối giữa hai vectơ.


5
Đây chính xác là những gì hàm atan2 () thực hiện cho bạn. :)
Nathan Reed

@NathanReed, yeah, nhưng bạn không thể sử dụng phương pháp này với một sản phẩm chấm để tránh chi phí quá cao?
jdk1.0

0

Có lẽ tôi nên đăng một câu hỏi hơi khác và tự trả lời nó; đây là câu hỏi gần nhất tôi có thể tìm được cho câu hỏi mà tôi có.

Tôi đang thực hiện công việc 2D trong khung vẽ html, nơi tôi có các góc xoay theo radian chứ không phải vectơ. Tôi cần "góc quay" (ta) để đi từ "tiêu đề hiện tại" (h) đến "tiêu đề mục tiêu" (t).

Đây là giải pháp của tôi:

var ta = t - h,
    ata = Math.abs(ta)
;
if (ta > Math.PI) ta = (ta / ata) * (Math.PI - ata)
return ta;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.