ฉันจะดักจับวัตถุด้วยการเคลื่อนที่เป็นวงกลมได้อย่างไร


23

ฉันกำลังสร้างเกมอวกาศ 2 มิติและต้องทำให้ยานอวกาศดักจับดาวเคราะห์ ฉันมีรหัสการทำงานสำหรับการสกัดกั้นเส้นตรง แต่ไม่สามารถหาวิธีคำนวณตำแหน่งของดาวเคราะห์ในวงโคจรเป็นวงกลมได้

เกมไม่ถูกต้องทางวิทยาศาสตร์ดังนั้นฉันจึงไม่กังวลเกี่ยวกับความเฉื่อยแรงโน้มถ่วงวงโคจรรูปไข่ ฯลฯ

ฉันรู้ตำแหน่งยานอวกาศและความเร็วรวมถึงดาวเคราะห์วงโคจร (Radius) และความเร็ว

enter image description here


1
ไม่ฉันกำลังพยายามคำนวณมุมที่เรือต้องเคลื่อนที่เพื่อสกัดกั้นดาวเคราะห์
Ausa

4
นี่อาจจะทำงานได้ดีขึ้นใน math.stackexchange.com ..
Jari Komppa

2
เรือของคุณสามารถเปลี่ยนความเร็วและทิศทางหรือเป็นค่าคงที่ได้หรือไม่? นอกจากนี้คำถามเกี่ยวกับการหลีกเลี่ยงการใช้ขีปนาวุธเป็นวงกลมนั้นอาจเป็นประโยชน์
thegrinner

4
เพื่อชี้แจงสถานการณ์เป็นอย่างไร มอบให้แก่โลก: ศูนย์กลางวงโคจร, รัศมีวงโคจร, ความเร็วเชิงมุม, ตำแหน่งปัจจุบัน; สำหรับเรือรบ : ตำแหน่งปัจจุบันความเร็วปัจจุบัน; กำหนดทิศทางของการเคลื่อนไหวสำหรับเรือเพื่อสกัดกั้นดาวเคราะห์
AakashM

6
ในฐานะที่เป็นบันทึกประวัติศาสตร์ที่น่าสนใจ: ดาวเคราะห์มักหมุนไปในทิศทางเดียวกันกับวงโคจรของพวกมันซึ่งเป็นทวนเข็มนาฬิกาเมื่อมองจากซีกโลกเหนือ จากความเป็นจริงนี้เราสามารถอนุมานว่าsundials ถูกคิดค้นในซีกโลกเหนือ หากว่านาฬิกาแดดถูกประดิษฐ์ขึ้นในซีกโลกใต้แล้วทวนเข็มนาฬิกาก็เป็นอีกทางหนึ่ง
Eric Lippert

คำตอบ:


3

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

เรือสามารถไปถึงจุดที่ใกล้ที่สุดบนวงโคจรในเวลาt_min :

shipOrbitRadius = (ship.position - planet.orbitCenter).length;
shortestDistance = abs(shipOrbitRadius - planet.orbitRadius);
t_min = shortestDistance/ship.maxSpeed;

เรือสามารถไปถึงจุดใดก็ได้บนวงโคจรในเวลาน้อยกว่าหรือเท่ากับt_max :

(ที่นี่เพื่อความเรียบง่ายฉันคิดว่าเรือสามารถขับผ่านดวงอาทิตย์ได้ถ้าคุณต้องการหลีกเลี่ยงสิ่งนี้คุณจะต้องเปลี่ยนไปใช้เส้นทางที่ไม่ใช่เส้นตรงอย่างน้อยในบางกรณี "วงจูบ" อาจดูดีและโคจร กลไก -y โดยไม่ต้องเปลี่ยนอัลกอริทึมมากกว่าปัจจัยคงที่)

if(shipOrbitRadius > planet.orbitRadius)
{
   t_max = planet.orbitRadius * 2/ship.maxSpeed + t_min;
}
else
{
   t_max = planet.orbitRadius * 2/ship.maxSpeed - t_min;
}

หากระยะเวลาการโคจรของเราสั้นเราอาจสามารถปรับปรุงขอบเขตบนนี้ได้โดยเลือกที่t_maxจะเป็นครั้งแรกหลังจากt_minนั้นดาวเคราะห์ก็เข้าใกล้จุดเริ่มต้นของเรือมากที่สุด ใช้ค่าใดของค่าสองค่าt_maxนี้ที่น้อยกว่า ดูคำตอบนี้ในภายหลังเพื่อหาสาเหตุของการทำงาน

ตอนนี้เราสามารถใช้การค้นหาแบบไบนารีระหว่างขั้วเหล่านี้t_minและt_max เราจะค้นหาค่า t ที่ทำให้เกิดข้อผิดพลาดใกล้กับศูนย์:

error = (planet.positionAtTime(t) - ship.position).squareMagnitude/(ship.maxSpeed*ship.maxSpeed) - t*t;

(การใช้โครงสร้างนี้ข้อผิดพลาด @ t_min> = 0 และข้อผิดพลาด @ t_max <= 0 ดังนั้นจะต้องมีอย่างน้อยหนึ่งจุดตัดที่มีข้อผิดพลาด = 0 สำหรับค่า t ในระหว่าง)

ฟังก์ชั่นตำแหน่งเป็นอะไรที่ ...

Vector2 Planet.positionAtTime(float t)
{
  angle = atan2(startPosition - orbitCenter) + t * orbitalSpeedInRadians;
  return new Vector2(cos(angle), sin(angle)) * orbitRadius + orbitCenter;
}

โปรดทราบว่าหากระยะเวลาการโคจรของดาวเคราะห์สั้นมากเมื่อเทียบกับความเร็วของเรือฟังก์ชั่นข้อผิดพลาดนี้อาจเปลี่ยนสัญญาณหลายครั้งในช่วงจาก t_min ถึง t_max ติดตามคู่ที่เร็วที่สุด & ve ได้ที่คุณพบและทำการค้นหาต่อไปเรื่อย ๆ จนกว่าข้อผิดพลาดจะใกล้ถึงศูนย์ ("ใกล้พอ" ที่ไวต่อหน่วยของคุณและบริบทการเล่นเกมตารางครึ่งระยะเวลาเฟรมอาจ ทำงานได้ดี - ช่วยให้มั่นใจว่าการสกัดกั้นนั้นแม่นยำภายในเฟรม)

เมื่อคุณมีข้อผิดพลาดในการลดความผิดพลาดได้ดีคุณสามารถชี้เรือไปที่ดาวเคราะห์ได้ตำแหน่งเวลา (t) และเร่งความเร็วเต็มที่มั่นใจว่าโลกจะไปถึงจุดนั้นในเวลาเดียวกันกับที่คุณทำ

คุณสามารถค้นหาวิธีแก้ปัญหาภายในการวนซ้ำ Log_2 ((2 * orbitRadius / ship.maxSpeed) / errorThreshold) ตัวอย่างเช่นถ้าเรือของฉันสามารถเคลื่อนที่วงโคจรใน 60 เฟรมและฉันต้องการการสกัดกั้นที่แม่นยำภายในหนึ่งเฟรมฉันจะต้องใช้การประมาณ 6 ครั้ง


1
คำตอบที่ดีมากมายที่นี่ยังมีตัวเลือกอื่น ๆ ที่น่าสนใจ แต่จากสิ่งที่ฉันมีอยู่แล้วโซลูชันนี้ดูดีที่สุดสำหรับอินสแตนซ์ของฉัน ฉันได้สร้างตัวอย่าง JavaScript ของผลลัพธ์ของฉัน การสาธิต
Ausa

11

อย่ามายุ่งกับเรื่องนี้ นี่ไม่ใช่วิธีการแก้ปัญหา "สมบูรณ์แบบ" แต่ควรใช้กับเกมส่วนใหญ่และความไม่สมบูรณ์ใด ๆ ที่ผู้เล่นมองไม่เห็น

if(!OldTargetPoint)
  TargetPoint = PlanetPosition;
else
  TargetPoint = OldTargetPoint;
Distance = CurPosition - TargetPoint;
TimeNeeded = Distance / Speed;
TargetPoint = PlanetPositionInFuture(TimeNeeded);
SteerTowards(TargetPoint);
[...repeat this every AI update, for example every second...]
  1. คำนวณเวลาที่จำเป็นในการเข้าถึงจุดเป้าหมาย
  2. คำนวณตำแหน่งของดาวเคราะห์ในเวลาที่คำนวณ
  3. เลื่อนไปยังจุดที่คำนวณ
  4. ทำซ้ำ

สิ่งนี้ใช้ได้ผลเพราะยานอวกาศใกล้เข้ามาถึงจุดต่ำสุดความผิดพลาดจะสูงขึ้น ดังนั้นการคำนวณจึงมีเสถียรภาพมากขึ้นเมื่อเวลาผ่านไป

ข้อผิดพลาดคือความแตกต่างระหว่างเวลาที่ต้องการจากการคำนวณเพื่อไปยังดาวเคราะห์ (TimeNeeded) และเวลาที่แท้จริงในการเข้าถึงโลก (หลังจากพิจารณา TargetPoint ใหม่)


1
คุณอาจต้องการเรียกใช้การวนซ้ำ 2 ครั้งเมื่อเริ่มต้นการสกัดกั้นมิฉะนั้นคุณอาจเห็นการสั่นของเรือรบระหว่างสองทิศทางชั่วขณะ (การเดาครั้งที่สองอาจดีกว่าครั้งแรกมากและส่งผลให้เกิดหัวเรื่องที่แตกต่างกันมาก อยู่ใกล้กับหรือภายในวงโคจรของดาวเคราะห์)
DMGregory

1
@DMGregory โอ้! เราสามารถใช้ตำแหน่งปัจจุบันของดาวเคราะห์แทน Orbit Center เป็นจุดเริ่มต้น เมื่อเราอยู่ใกล้ที่อยู่ใกล้มากถ้าเราอยู่ไกลมันไม่สำคัญ
API-Beast

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

3

เริ่มกันเลยโดยการดูคณิตศาสตร์ที่อยู่เบื้องหลังปัญหา

ขั้นตอนที่ 1:

การหาจุดตัดระหว่างเส้นและรูปร่างเป็นเพียงการแทรกสมการของเส้นตรงในสมการของรูปร่างซึ่งเป็นวงกลมในกรณีนี้

Line intersecting with circle

ใช้วงกลมที่มีศูนย์และรัศมีR จุดpอยู่บนวงกลมถ้า

|pc|2=r2

p=p0+μv

|p0+μvc|2=r2

ระยะทางยกกำลังสองสามารถเขียนใหม่เป็นผลิตภัณฑ์แบบจุด ( http://en.wikipedia.org/wiki/Dot_product )

(p0+μvc)(p0+μvc)=r2

a=cp0(μva)(μva)=r2

μ2(vv)2μ(av)+aa=r2

|v|=1

μ22μ(av)+|a|2r2=0

ซึ่งเป็นสมการกำลังสองอย่างง่ายและเรามาถึงวิธีแก้ปัญหา

μ=av+sqrt((av)2a2r2)

μ<0เส้นของเรือในกรณีของคุณไม่ได้ตัดกับวงโคจรของดาวเคราะห์

μ=0บรรทัดของเรือจะสัมผัสวงกลมในจุดเดียว

μค่าที่สอดคล้องกับจุดสองจุดบนวงโคจร!

ขั้นตอนที่ 2:

μ

เราสามารถทำอะไรกับเรื่องนี้? ทีนี้เรารู้ระยะทางที่เรือต้องเดินทางและจุดใดที่จะสิ้นสุดลง!

p=p0+μvμv

ทีนี้สิ่งที่เหลือไว้ให้ทำก็คือการคำนวณว่าดาวเคราะห์ควรอยู่ที่ไหนเมื่อเรือเริ่มเข้าสู่วงโคจรของมัน สิ่งนี้คำนวณได้อย่างง่ายดายด้วยPolar coodinates ที่เรียกว่า( http://mathworld.wolfram.com/PolarCoordinates.html )

x=c+rcos(θ)

y=c+rsin(θ)

tangularVelocity

สรุป

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


8
การวิเคราะห์ที่ดี แต่ดูเหมือนว่าจะไม่ตอบคำถาม (ให้ความกระจ่างในความคิดเห็น): "ไม่ฉันกำลังพยายามคำนวณมุมที่เรือต้องเคลื่อนที่เพื่อสกัดกั้นโลก" คุณกำลังทำมุมของเรือตามที่กำหนดและคำนวณตำแหน่งของดาวเคราะห์แทนที่จะเป็นมุมมองรอบ ๆ
Chaosed0

4
ไม่ไปลงคะแนนเพราะเป็นการวิเคราะห์ที่มีประโยชน์ แต่ฉันเห็นด้วยกับ @ Chaosed0 ว่าไม่ได้ตอบคำถาม ในการสรุปของคุณคุณพูดว่า "เลือกบรรทัดสำหรับเรือของคุณ ... " แต่การเลือกบรรทัดนั้นเป็นส่วนที่ยาก
Drake

1

ต่อไปนี้เป็นวิธีแก้ปัญหา "ออกนอกกรอบ" เล็กน้อยสองรายการ

คำถามคือเมื่อเรือเคลื่อนที่เป็นเส้นตรงด้วยความเร็วที่กำหนดและดาวเคราะห์เคลื่อนที่เป็นวงกลมที่มีรัศมีที่ความเร็วเชิงมุมที่กำหนดและตำแหน่งเริ่มต้นของดาวเคราะห์และเรือกำหนดทิศทางของเวกเตอร์ของเรือ เส้นตรงควรอยู่ในการวางแผนการสกัดกั้น

แนวทางที่หนึ่ง: ปฏิเสธหลักฐานของคำถาม ปริมาณที่ "เลื่อนได้" ในคำถามคือมุม แต่แก้ไขให้ดี ชี้เรือตรงไปที่ศูนย์กลางของวงโคจร

  • คำนวณตำแหน่งที่เรือจะเผชิญหน้ากับดาวเคราะห์ นั่นเป็นเรื่องง่าย
  • คำนวณระยะทางจากเรือไปยังตำแหน่งสกัดกั้น ยังง่าย
  • คำนวณเวลาที่ใช้จนกว่าดาวเคราะห์จะไปถึงตำแหน่งดัก ง่าย.
  • แบ่งระยะทางจากเรือถึงจุดตัดตามเวลาจนกว่าดาวเคราะห์จะถึงจุดตัด
  • ถ้ามันเล็กกว่าหรือเท่ากับความเร็วสูงสุดของเรือคุณก็เสร็จแล้ว ตั้งเรือที่เคลื่อนที่ด้วยความเร็วนั้นตรงเข้าหาดวงอาทิตย์
  • มิฉะนั้นให้เพิ่มระยะเวลาการโคจรของดาวเคราะห์เข้ากับเวลาแล้วลองอีกครั้ง ทำเช่นนั้นต่อไปจนกว่าคุณจะได้ความเร็วที่เพียงพอสำหรับเรือ

แนวทางที่สอง: อย่าใช้งานกับระบบอัตโนมัติเลย สร้างมินิเกมที่ผู้เล่นจะต้องใช้เครื่องขับดันเพื่อเข้าหาดาวเคราะห์และหากพวกเขาตีมันด้วยความเร็วที่สูงเกินไปพวกเขาจะระเบิด แต่พวกเขาก็มีเชื้อเพลิง จำกัด เช่นกัน ทำให้ผู้เล่นเรียนรู้วิธีการแก้ปัญหาดักจับ!


1

หากคุณไม่ต้องการใช้พิกัดเชิงขั้วให้พิจารณาว่าตำแหน่งที่เป็นไปได้ทั้งหมดของเรือเป็นรูปกรวย (x,Y,เสื้อ)ช่องว่าง สมการนี้คือ

เสื้อโวลต์=x2+Y2

ที่ไหน โวลต์คือความเร็วของเรือ จะถือว่าเรือเริ่มต้นที่ศูนย์

ตำแหน่งของดาวเคราะห์ในอวกาศและเวลาสามารถถูกทำให้เป็นจุดได้โดยเช่น

x=x0+Rโอs(Wยู+a)Y=Y0+Rsผมn(Wยู+a)เสื้อ=ยู

ที่ไหน ยู ไปจาก 0 สูงกว่า W คือความเร็วเชิงมุมและ aคือมุมเริ่มต้นของดาวเคราะห์ ณ เวลาศูนย์ จากนั้นแก้ปัญหาที่เรือและดาวเคราะห์สามารถพบกันในเวลาและสถานที่ คุณได้สมการยู เพื่อแก้ปัญหา:

uv=(x0+rcos(wu+a))2+(y0+rsin(wu+a))2u2v2=(x0+rcos(wu+a))2+(y0+rsin(wu+a))2u2v2=x02+y02+r2+2x0rcos(wu+a)+2y0rsin(wu+a)

This equation needs to be solved numerically. It may have many solutions. By eyeballing it, it seems it always has a solution


1

Here's part of a solution. I didn't get to finish it in time. I'll try again later.

If I understand correctly, you have a planet's position & velocity, as well as a ship's position and speed. You want to get the ship's movement direction. I'm assuming the ship's and planet's speeds are constant. I also assume, without loss of generality, that the ship is at (0,0); to do this, subtract the ship's position from the planet's, and add the ship's position back onto the result of the operation described below.

Unfortunately, without latex, I can't format this answer very well, but we'll attempt to make do. Let:

  • s_s = the ship's speed (s_s.x, s_s.y, likewise)
  • s_a = the ship's bearing (angle of movement, what we want to calculate)
  • p_p = the planet's initial position, global coords
  • p_r = the planet's distance (radius) from the center of orbit, derivable from p_p
  • p_a = the planet's initial angle in radians, relative to the center of orbit
  • p_s = the planet's angular velocity (rad/sec)
  • t = the time to collision (this turns out to be something we must calculate as well)

Here's the equations for the position of the two bodies, broken down into components:

ship.x = s_s.x * t * cos(s_a)
ship.y = s_s.y * t * sin(s_a)

planet.x = p_r * cos(p_a + p_s * t) + p_p.x
planet.y = p_r * sin(p_a + p_s * t) + p_p.y

Since we want ship.x = planet.x and ship.y = planet.y at some instant t, we obtain this equation (the y case is nearly symmetrical):

   s_s.x * t * cos(s_a) = p_r * cos(p_a + p_s * t) + p_p.x
   s_s.y * t * sin(s_a) = p_r * sin(p_a + p_s * t) + p_p.y

Solving the top equation for s_a:

   s_s.x * t * cos(s_a) = p_r * cos(p_a + p_s * t) + p_p.x
=> s_a = arccos((p_r * cos(p_a + p_s * t) + p_p.x) / (s_s.x * t))

Substituting this into the second equation results in a fairly terrifying equation that Wolfram alpha won't solve for me. There may be a better way to do this not involving polar coordinates. If anyone wants to give this method a shot, you're welcome to it; I've made this a wiki. Otherwise, you may want to take this to the Math StackExchange.


2
I would love to have TeX enabled for this site. It would make some graphics related stuff (e.g. vector, matrices, quaternions..) easier to represent.
mvw

0

I would fix the location at which to intercept (graze the circle, at the "outgoing" side of the orbit.)

Now you just have to adjust the spaceship's speed so that planet and ship reach that point at the same time.

Note that the rendez-vous could be after N more orbits, depending how far away the ship is, and how fast the planet is orbiting the star.

Pick the N that in time, comes nearest to the ship's journey duration at current speed.

Then speed up or slow down ship to match the timestamp for those N orbits exactly.

In all this, the actual course is already known! Just not the speed.


This could give unnecessarily long trips. Let's say we're positioned so that the planet is coming toward us and we can actually reach the "incoming" grazing point at the same time the planet does. If we're only looking at the "outgoing" grazing point, then we could end up spending half an extra half a year in transit!
DMGregory

True... depends on orbital speeds. But it also minimizes the delta-speed if you always graze at outgoing. At "incoming" you could burn up in the atmosphere, whereas in "outgoing" you are more likely to be matched. @DMGregory
Bram
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.