ฉันจะคำนวณมุมและทิศทางการเลี้ยวที่เหมาะสมระหว่างสองเวกเตอร์ 2D ได้อย่างไร


26

ฉันกำลังทำงานกับการเคลื่อนไหว AI ที่ไม่มีสิ่งกีดขวางและการเคลื่อนไหวถูก จำกัด ไว้ที่ระนาบ XY ฉันกำลังคำนวณเวกเตอร์สองตัวคือv , ทิศทางหันหน้าของเรือ 1 และwเวกเตอร์ชี้ไปจากตำแหน่งของเรือ 1 ถึงเรือ 2

ฉันกำลังคำนวณมุมระหว่างเวกเตอร์สองตัวนี้โดยใช้สูตร

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

ปัญหาที่ฉันพบคือการarccosคืนค่าระหว่าง 0 ถึง 180 °เท่านั้น นี่ทำให้เป็นไปไม่ได้ที่จะตัดสินว่าฉันควรเลี้ยวซ้ายหรือขวาเพื่อเผชิญหน้ากับเรือรบลำอื่น

มีวิธีที่ดีกว่าในการทำเช่นนี้?


1
Mathf.DeltaAngle()หากคุณกำลังใช้ความสามัคคีให้ตรวจสอบ
Russell Borogove

คำตอบ:


22

มันเร็วกว่าที่จะใช้ 2d cross-product ไม่มีฟังก์ชั่น Trig ที่มีราคาแพง

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

atan2หากคุณยังต้องการมุมที่เกิดขึ้นจริงผมขอแนะนำให้ใช้ atan2จะให้มุมที่แน่นอนของเวกเตอร์ใด ๆ เพื่อให้ได้มุมที่สัมพันธ์กันระหว่างเวกเตอร์ใด ๆ ให้คำนวณมุมที่แน่นอนของพวกมันและใช้การลบอย่างง่าย

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
หลังจากที่ได้อ่านคำตอบ @ Tetrad arccosของฉันคิดว่าคุณสามารถรวมสินค้าข้ามและ ด้วยวิธีนี้คุณจะใช้เพียงหนึ่งฟังก์ชันทริกเกอร์ แต่ก็ยังมีมุมที่แท้จริง อย่างไรก็ตามฉันขอแนะนำให้ใช้การเพิ่มประสิทธิภาพนี้จนกว่าคุณจะแน่ใจว่าคุณการติดตามมุม AI นั้นส่งผลกระทบต่อประสิทธิภาพของเกมอย่างเห็นได้ชัด
deft_code

2
ใช่เมื่อแปลงระหว่างเวกเตอร์กับมุม atan2 () เป็นเพื่อนของคุณแน่นอนที่สุด
bluescrn

1
ขอบคุณ! ฉันพบว่าจริง ๆ แล้วฉันไม่ต้องการมุมการคว้าผลิตภัณฑ์ Cross 2D นั้นง่ายพอสำหรับความต้องการของฉัน
ข้อผิดพลาด 454

2
นอกจากนี้การตรวจสอบif( cross == -0.0f )vs ของคุณก็if( cross == 0.0f )ดูบอบบางมากเช่นกัน
bobobobo

1
@bobobobo ด้วยเอนจิ้นฟิสิกส์มันอาจไม่ใช่ตัวเลือกเพียงแค่เลือกทิศทางและเคลื่อนย้าย การหมุนอย่างน่าอัศจรรย์อาจทำให้เครื่องยนต์ฟิสิกส์หลุดพ้น นอกจากนี้การหมุนอย่างน่าอัศจรรย์ก็ดูน่ากลัวสำหรับภาพเคลื่อนไหวด้วยเช่นกัน ใช่คุณสามารถแก้ปัญหานี้ได้โดยไม่ต้องใช้ความคิดทางซ้ายหรือขวา แต่วิธีการขัดมันมักจะต้องการสิ่งเหล่านี้
deft_code

10

ใช้ arcsin ของผลิตภัณฑ์ Cross 2D (เช่นองค์ประกอบ z ของเวกเตอร์ผลิตภัณฑ์ข้าม) นั่นจะให้ -90 ถึง 90 ซึ่งจะแจ้งให้คุณทราบว่าจะไปทางซ้ายหรือขวา

ระวังเพราะ A cross B นั้นไม่เหมือนกับ B cross A

กลยุทธ์อื่น (แต่อาจไม่ตรงไปตรงมา) คือการคำนวณ "หัวเรื่อง" ของเวกเตอร์สองตัวโดยใช้ atan2 แล้วหาว่าการชี้ที่ X องศาจำเป็นต้องไปทางซ้ายหรือขวาเพื่อไปที่ B ชี้ไปที่องศา y


ขอบคุณสำหรับคำตอบ เพื่อให้ชัดเจนสำหรับเบราว์เซอร์ในอนาคตการใช้อินเวอร์สไซน์ของขนาดของผลิตภัณฑ์ข้าม 2 มิติจะให้ค่าระหว่าง 0 ถึง 90 การถ่ายไซน์ขององค์ประกอบ z ขององค์ประกอบข้าม 2d ให้ผลลัพธ์ที่ต้องการ
ข้อผิดพลาด 454

@Error 454 คุณพูดถูกต้องแล้วแก้ไขโพสต์ของฉัน
Tetrad

1

ใช้เวกเตอร์เพื่อเปลี่ยนเส้นทางเรือ นี่คือการทำงานของ "พฤติกรรมการหมุนพวงมาลัย" - คุณไม่จำเป็นต้องคำนวณมุมแค่ใช้เวกเตอร์ที่คุณมี นี่คือการคำนวณที่ถูกกว่ามาก

เวกเตอร์w(เวกเตอร์จาก Ship 1 to Ship 2) เป็นข้อมูลทั้งหมดที่คุณต้องการ การปรับเปลี่ยนทั้งเรือความเร็ว 1 เวกเตอร์หรือจัดส่งเร่งเวกเตอร์ 1 (หรือแม้กระทั่งเวกเตอร์หัวโดยตรง) wโดยใช้รุ่นถ่วงน้ำหนักของ

ป้อนคำอธิบายรูปภาพที่นี่

ขนาดของวิธีการห่างไกลออกไปจากเรือที่ 1 คือปิดหลักสูตร (วีว่าไม่ดีไม่ตรงกับ W) สามารถพบได้โดยใช้ ( 1 - dot(v,w))

  • ( dot(v,w)ถูกขยายให้ใหญ่สุดเมื่อใดvและเข้าwแถวกันทุกประการ)
  • ( 1 - dot(v,w)) ให้ 0 เมื่อvและwเรียงกันให้vและwเป็นมาตรฐาน)

0

มีวิธีง่ายๆในการหามุมที่แน่นอนของเวกเตอร์ผ่านเรขาคณิตปกติ

เช่น vector V = 2i - 3j;

ค่าสัมบูรณ์ของสัมประสิทธิ์ x = 2;

ค่าสัมบูรณ์ของค่าสัมประสิทธิ์ y = 3;

มุม = atan (2/3); [มุมจะอยู่ระหว่าง 0 ถึง 90]

ขึ้นอยู่กับมุมควอดเรนจะมีการเปลี่ยนแปลง

ถ้า (x สัมประสิทธิ์ <0 และ y สัมประสิทธิ์> 0) แล้ว angle = 180-angle;

ถ้า (x สัมประสิทธิ์ <0 และ y สัมประสิทธิ์ <0) แล้ว angle = 180 + angle;

ถ้า (x สัมประสิทธิ์> 0 และ y สัมประสิทธิ์ <0) แล้ว angle = 360-angle;

ถ้า (x สัมประสิทธิ์> 0 และ y สัมประสิทธิ์> 0) แล้ว angle = angle;

หลังจากหามุมของเวกเตอร์ที่หนึ่งและสองแล้วให้ลบมุมเวกเตอร์แรกจากเวกเตอร์ที่สอง จากนั้นคุณจะได้มุมที่แน่นอนระหว่างเวกเตอร์สองตัว


5
นี่คือสิ่งที่ฟังก์ชั่น atan2 () ใช้สำหรับคุณ :)
นาธานรีด

@NathanReed ใช่ แต่คุณไม่สามารถใช้วิธีนี้กับผลิตภัณฑ์ดอทเพื่อหลีกเลี่ยงค่าใช้จ่ายตรีโกณมิติใช่หรือไม่
jdk1.0

0

บางทีฉันควรโพสต์คำถามที่แตกต่างกันเล็กน้อยและตอบด้วยตนเอง; นี่เป็นคำถามที่ใกล้เคียงที่สุดที่ฉันสามารถหาได้ในคำถามที่ฉันมี

ฉันกำลังทำงาน 2D ในผ้าใบ html ที่ฉันมีมุมการหมุนเป็นเรเดียนแทนที่จะเป็นเวกเตอร์ ฉันต้องการ "มุมเลี้ยว" (ta) เพื่อรับจาก "หัวเรื่องปัจจุบัน" (h) ถึง "หัวเรื่องส่วนหัว" (t)

นี่คือทางออกของฉัน:

var ta = t - h,
    ata = Math.abs(ta)
;
if (ta > Math.PI) ta = (ta / ata) * (Math.PI - ata)
return ta;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.