Dairesel hareketlerle nesneyi nasıl yakalayabilirim


23

2 boyutlu bir uzay oyunu yaratıyorum ve uzay gemisinin bir gezegene müdahale etmesi gerekiyor. Düz hat kesişimleri için çalışma kodum var ancak gezegenlerin dairesel bir yörüngede nasıl hesaplanacağını çözemiyorum.

Oyun bilimsel olarak doğru değil, bu yüzden atalet, yerçekimi, eliptik yörüngeler, vb. İçin endişelenmiyorum.

Uzay gemilerinin yerini ve hızını ve ayrıca gezegenlerin yörüngesini (Radius) ve hızını biliyorum.

enter image description here


1
Hayır Geminin gezegeni engellemek için hareket etmesi gereken açıyı hesaplamaya çalışıyorum.
Ausa

4
Bu muhtemelen math.stackexchange.com adresinde daha iyi sonuç verir ..
Jari Komppa

2
Geminiz hız ve yön değiştirebiliyor mu, yoksa bunlar sabit mi? Ayrıca, füzelerin hedef almasını engellemeyle ilgili bu soru yararlı olabilir.
thegrinner

4
Netleştirmek için durum mu? gezegen için verilen : yörünge merkezi, yörünge yarıçapı, açısal hız, mevcut konum; için gemiye : geçerli konum, akım hızı; gezegenin önünü kesmek için geminin hareket yönünü belirlemek
AakashM

6
İlginç bir tarihi not olarak: gezegenler genellikle yörüngeleriyle aynı yönde dönerler, bu nedenle kuzey yarımkürenin yukarısından da görüldüğü gibi saat yönünün tersi de geçerlidir. Bu durumdan, kuzey yarımkürede güneş saatlerinin icat edildiğini anlayabiliriz . Güney yarımkürede güneş saatleri icat edilseydi saat yönünde başka türlü olabilirdi .
Eric Lippert

Yanıtlar:


3

Buna analitik bir çözüm zordur, ancak istenen doğrulukta bir çözüm bulmak için ikili arama kullanabiliriz .

Gemi t_min zamanında yörüngedeki en yakın noktaya ulaşabilir :

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

Gemi yörüngedeki herhangi bir noktaya t_max değerine eşit veya daha az sürede ulaşabilir :

(Burada, basitlik için, geminin güneşten geçebileceğini varsayıyorum. Bundan kaçınmak istiyorsan, en azından bazı durumlar için düz olmayan yollara geçmen gerekecek. "Öpüşen daire" güzel ve yörüngeye benzeyebilir. mechanics-y, algoritmayı sabit bir faktörden daha fazla değiştirmeden)

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

Yörünge periyodumuz kısaysa, gezegenin geminin başlangıç ​​konumuna en yakın yaklaşmasını sağlamasının t_maxardından ilk defa olmasını seçerek bu üst sınır üzerinde gelişebiliriz t_min. Bu iki değerden hangisi t_maxdaha küçükse onu alın. Bunun neden işe yaradığının bir türevi için bu cevaba bakınız.

Şimdi bu aşırı uçlar, t_min ve t_max arasında ikili aramayı kullanabiliriz . Hatayı sıfıra yaklaştıracak bir t değeri arayacağız :

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

(Bu yapı kullanılarak, hata @ t_min> = 0 ve hata @ t_max <= 0, bu nedenle aradaki bir t değeri için en az bir hata = 0 olan bir kesme olmalıdır)

tamlık için pozisyon işlevi ...

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

Gezegenin yörünge periyodunun geminin hızına göre çok kısa olması durumunda, bu hata fonksiyonunun aralık boyunca t_min'den t_max'a kadar işaretleri birkaç kez değiştirebileceğini unutmayın. Sadece karşılaştığınız en eski + ve -veve çiftlerini takip edin ve hata sıfıra yakın olana kadar aralarında aramaya devam edin ("yeterince yakın" ünitelerinize ve oyun bağlamınıza duyarlı olmak. Kare süresinin yarısı karesi olabilir. iyi çalışın - bu müdahalenin bir çerçeve içinde doğru olmasını sağlar)

Hatayı en aza indirgeyen bir kez, gemiyi planet.positionAtTime (t) 'ye yönlendirebilir ve tam gaz kullanıp, gezegenin aynı zamanda bu noktaya ulaşacağından emin olabilirsiniz.

Log_2 ((2 * orbitRadius / ship.maxSpeed) / errorThreshold) yinelemelerinde her zaman bir çözüm bulabilirsiniz. Örneğin, eğer gemim yörüngeyi 60 kare içinde geçebiliyorsa ve bir kare içinde doğru bir kesişme noktası istiyorsam, yaklaşık 6 yinelemeye ihtiyacım olacak.


1
Burada çok iyi cevaplar var, ayrıca bazı ilginç alternatif seçenekler de var, fakat sahip olduklarımdan bu örnekler benim için en iyi çözüm. Sonuçlarımdan küçük bir JavaScript demosu oluşturdum. Demo
Ausa

11

Bunu fazla karmaşık hale getirmeyelim. Bu "mükemmel" bir çözüm değildir, ancak çoğu oyun için çalışmalı ve herhangi bir kusur oyuncuya görünmez olmalıdır.

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. Hedef noktaya ulaşmak için gereken süreyi hesaplayın.
  2. Gezegenin hesaplanan zamanda hangi pozisyonda olacağını hesaplayın.
  3. Hesaplanan noktaya doğru hareket edin.
  4. Tekrar et

Bu çalışır çünkü uzay aracı yaklaştıkça hata düşer. Böylece hesaplama zamanla daha istikrarlı hale gelir.

Hata, gezegene ulaşmak için hesaplanan gerekli süre (TimeNeeded) ile gezegene ulaşmak için gereken gerçek zaman (yeni Hedef Noktası dikkate alındıktan sonra) arasındaki farktır.


1
Bir kesişme parkuruna başlarken 2 yineleme yapmak isteyebilirsiniz, aksi halde gemiyi anlık olarak iki yöne doğru sallarsınız (ikinci tahmin birinciden çok daha iyi olabilir ve çok farklı bir rotaya neden olabilir - özellikle de gemi gezegenin yörüngesine yakın veya içinde)
DMGregory

1
@DMGregory Oh! Orbit Merkezi yerine şu anki Gezegen Konumunu başlangıç ​​noktası olarak alabiliriz. Yakın olduğumuzda bu daha yakın, eğer uzaktaysak önemli değil.
API-Canavar,

Gezegen gemi ile karşılaştırıldığında yavaşça hareket ettiğinde bunun en iyi şekilde çalıştığını belirtmek de önemlidir. Gezegenin hızı gemininkiyle karşılaştırılabilir veya daha büyükse, geminin yolunda salınımları görebilirsiniz. Patolojik hız oranlarında, gemi sonsuza dek eşmerkezli bir yörüngede gezegeni kovalayabilir. Gezegenleriniz hızlıysa ve bunun olduğunu fark ederseniz, uçuşun orta noktasını tekrarlamak yerine tüm engelleme rotasını önceden planlamak isteyebilirsiniz.
DMGregory

3

Sorunun ardındaki matematiğe göz atarak başlayalım.

Aşama 1:

Bir çizgi ile bir şekil arasındaki kesişme noktasını bulmak sadece çizginin denklemini, bu durumda bir çember olan şeklin denklemine sokmaktan ibarettir.

Line intersecting with circle

Merkezi c ve yarıçapı r olan bir daire alın . Daire üzerinde p noktası varsa,

|pc|2=r2

olarak ifade edilen bir çizgi ilep=p0+μv ( v'nin bir vektör olduğu http://en.wikipedia.org/wiki/Euclidean_vector ) daire formülüne ekler ve

|p0+μvc|2=r2

Kare uzaklık nokta ürünü olarak yeniden yazılabilir ( 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

ki bu basit bir ikinci dereceden denklemdir ve çözüme ulaşıyoruz.

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

μ<0

μ=0

Aksi takdirde, bu bize iki verir μ

Adım 2:

μ

Bununla ne yapabiliriz? Eh, şimdi geminin kat etmesi gereken mesafeyi ve hangi noktaya geleceğini biliyoruz!

p=p0+μvμv

Şimdi, tek yapılması gereken, geminin yörüngesine doğru gelmeye başladığında gezegenin nerede olması gerektiğini hesaplamak. Bu kolayca sözde hesaplanır Polar koordinatların ( http://mathworld.wolfram.com/PolarCoordinates.html )

x=c+rcos(θ)

y=c+rsin(θ)

tangularVelocity

özet

Geminiz için bir çizgi seçin ve gezegenin yörüngesine çarpıp çarpmadığını görmek için matematiği çalıştırın. Olursa, o noktaya ulaşmak için gereken süreyi hesaplayın. Geminin hareket etmeye başladığında gezegenin nerede olması gerektiğini hesaplamak için gezegenle bu noktadan yörüngeye geri dönmek için bu zamanı kullanın.


8
İyi analiz, ancak şu soruyu cevaplıyor gibi görünmüyor (bir yorumda açıklığa kavuşturuldu): "Hayır, gemiyi gezegene müdahale etmek için hareket etmesi gereken açıyı hesaplamaya çalışıyorum." Geminin açısını verilen gibi alıyorsunuz ve gezegenin konumunu değil, başka bir yoldan hesaplıyorsunuz.
0

4
Faydalı bir analiz olduğu için bunu reddetmeyeceğim, ancak soruyu cevaplamayacağı konusunda @ Chaosed0 ile aynı fikirdeyim. Özetinizde "Geminiz için bir hat seçin ..." diyorsunuz, ancak bu satırı seçmek tam olarak zor kısım.
Drake

1

İşte iki hafif "kutudan" çözümleri.

Soru şudur: Geminin belirli bir hızla düz bir çizgide hareket etmesi ve gezegenin belirli bir açısal hızda verilen yarıçap dairesinde hareket etmesi ve gezegenin ve geminin başlangıç ​​pozisyonları, geminin hangi yön vektörünü belirlediğine göre bir kesişme rotasını çizmek için düz çizgi bulunmalıdır.

Birinci çözüm: Sorunun öncülünü inkar edin. Soruda “kaygan” olan miktar açıdır. Bunun yerine, düzeltin. Gemiyi doğrudan yörüngenin ortasına doğrultun.

  • Geminin gezegene karşı karşıya kalacağı pozisyonu hesaplayın ; bu kolay.
  • Gemiden durma konumuna kadar olan mesafeyi hesaplayın; ayrıca kolay.
  • Gezegenin bir sonraki müdahale pozisyonuna gelene kadar alacağı süreyi hesaplayın. Kolay.
  • Gemiden kesişme noktasına olan mesafeyi gezegenin kesişme noktasına gelene kadar bölün.
  • Bu, geminin azami hızına eşit veya daha küçükse, işiniz bitmiştir. Gemiyi o hızla doğruca güneşe doğru hareket ettirin.
  • Aksi takdirde, gezegenin yörünge dönemini zamana ekleyin ve tekrar deneyin. Geminin sebebi olan bir hız elde edene kadar bunu yapmaya devam edin.

İkinci çözüm: Otomatik pilotta hiç yapma. Oyuncunun gezegene yaklaşmak için iticileri kullanması gereken bir mini oyun yapın ve eğer göreceli olarak çok yüksek bir hızda vururlarsa, havaya uçururlar, ancak aynı zamanda sınırlı yakıtları vardır. Oyuncunun engelleme problemini nasıl çözeceğini öğrenmesini sağlayın!


1

Kutupsal koordinatları kullanmak istemiyorsanız, geminin tüm olası konumlarının bir koni oluşturduğunu düşünün. (x,y,t)alanı. Bunun için denklem

tv=x2+y2

nerede vgemi hızıdır. Geminin sıfırdan başladığı varsayılıyor.

The position of the planet in space and time can be parametrized by e.g.

x=x0+rcos(wu+a)y=y0+rsin(wu+a)t=u

where u goes from 0 upwards. w is the angular speed and a is the starting angle of the planet at time zero. Then solve where the ship and planet could meet in time and space. You get an equation for u to solve:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.