Hedef Takibi: Dönen bir tareti ne zaman hızlandırmalı ve yavaşlatmalı?


24

Diyelim ki targetolarak tanımlanan hareketli bir daireselim var :

Vector2 position;
Vector2 velocity;
float radius;

Ve turretaşağıdaki gibi tanımlanan bir döner (bir tür hareketli araca monte edilmiş):

Vector2 position;
Vector2 velocity;
float angle; // radians
float angularVelocity; // radians per second
const float maxAngularVelocity; // radians per second
const float maxAngularAcceleration; // radians per second per second

(Ya da bu çizgiler boyunca bir şey. Her ikisinin de konum ve hızının başka bir yerde kontrol edildiğini unutmayın - hızın sabit olduğunu ve konumun hıza bağlı olarak değiştiğini varsayalım.)

Belirli bir çerçeveye belirlemek için iki ilgili AI işlevi yazmaya çalışıyorum:

  • Taretin hedefe işaret etmesini sağlamak için taretin açısına hangi açısal hızlanma (ve hangi yönde) uygulanmalıdır?

  • Hedef şu anda görüş alanındaysa, (yarıçapı içindeki herhangi bir kısım) xsaniyeler boyunca görüş alanında tutulabilir xmi, bir saniyenin kesri nerededir? (Alternatif olarak: Hedefin aslında “kilitlendiğini” ve yalnızca manzaraların üzerinden uçmasını sağlamayan başka bir strateji var mı?)

Ve biraz yardım kullanabilirim ...


1
Rotasyonel hızlanma ve yavaşlama için farklı değerlere sahip olabilirsiniz - gerçek dünyada biri muhtemelen motor, diğeri ise frendir.
e100

Yanıtlar:


19

Öncelikle, taret bakan yönü ile hedefe olan yön arasındaki açı farkını belirlemeniz gerekir.

Vector2 turretToTarget = target.position - turret.position;
float desiredAngle = atan2(turretToTarget.y, turretToTarget.x);
float angleDiff = desiredAngle - turret.angle;

// Normalize angle to [-PI,PI] range. This ensures that the turret
// turns the shortest way.
while (angleDiff < -PI) angleDiff += 2*PI;
while (angleDiff >= PI) angleDiff -= 2*PI;

Bu miktarlara sahip olduğunuzda, taret açısı için ikinci bir derece ifade ayarlayabilirsiniz. Her zaman en son konum ve hız verilerini kullandığınızdan emin olmak için bunu her güncellemede hesaplamanız gerekir.

// Compute angular acceleration.
const float C0 = // Must be determined.
const float C1 = // Must be determined.
float angularAcc = C0 * angleDiff - C1 * turret.angularVelocity;

Burada, ivme ifadesindeki ilk terim (sıfır derece) taretin hedefe doğru dönmeye başlamasına neden olacaktır. Ancak, zaman içinde durmayacak, daha ziyade ileri geri salınacak. Durdurmak için yüksek dönme hızının yüksek bir ivmelenme ile karşı karşıya kalmasına neden olan ikinci terim sönümlemesine (birinci derece) ihtiyacımız var.

Şimdi, sistemin iyi çalışmasını sağlamak için pozitif sabitlerin (mutlaka program sabitleri olması gerekmez) belirlenmesi ve dengelenmesi gerekir. C0sistemin hızının ana kontrolüdür. İçin yüksek bir değer C0hızlı bir dönüş hızı sağlayacak ve düşük bir değer düşük bir dönüş hızı sağlayacaktır. Gerçek değer birçok faktöre bağlıdır, bu yüzden burada deneme yanılma kullanmanız gerekir. C1sönümleme büyüklüğünü kontrol eder. İkinci dereceden denklemin ayırt edici özelliği bize C1*C1 - 4*C0 >= 0salınım yapmayan bir sistemimiz olduğunu söyler .

// New definition.
const float C1 = 2*sqrt(C0); // Stabilizes the system.

C1Sayısal nedenlerden ötürü muhtemelen bundan biraz daha büyük bir seçim yapmalısınız , ancak çok büyük değil çünkü bunun yerine aşırı sönümlenir ve yavaş yanıt verebilir. Yine, ince ayar yapmanız gerekir.

Ayrıca, bu kodun yalnızca açısal ivmeyi hesapladığına dikkat etmek önemlidir. Açı ve açısal hız, başka bir yerden, bir çeşit bütünleştirici kullanarak ve bununla güncellenmelidir. Sorudan, bunun ele alındığını varsayıyorum.

Sonunda, gecikme hakkında söylenecek bir şey var, çünkü hızlı bir hedefi takip ederken taret muhtemelen her zaman geride olacak. Bununla baş etmenin basit bir yolu, hedefin konumuna doğrusal bir tahmin eklemek, yani her zaman hedefin ileri yönünde bir miktar ileriye doğru hedeflemektir.

// Improvement of the first lines above.
const float predictionTime = 1; // One second prediction, you need to experiment.
Vector2 turretToTarget = target.position + predictionTime * target.velocity - turret.position;
/// ...

Hedef yarıçapında hedeflenen tareti bir süre tutmaya gelince, bu doğrudan bu tür bir sisteme dayatılması zor bir gereklilik olabilir. Bu kontrolörün, tareti hedefe (ya da öngörülen pozisyona) yönelik olarak tutmaya çalışacağından emin olabilirsiniz. Sonuç tatmin edici olmadığı ortaya çıkarsa sen parametrelerini değiştirmek zorunda predictionTime, C0ve C1(stabil sınırları içinde).


Bunun doğru olup olmadığını söylemeye yetkim yok, ama zekice şeyler gibi geliyor! Geçmişte bu tür problemleri, ivmenin ne zaman ne hızlanacağını ve "sonları ne zaman uygulayacağınızı" hesaplamanın etkisini önceden tahmin ederek çözdüm. Bu yanlış yaptığım anlamına mı geliyor?
Iain

Atan2 bu yöntemin öngörücü bir sisteme adapte olmasını zorlaştırır çünkü atan2'ye x ve y parametreleri t'ye bağımlıdır.
Skizz

Bu tam olarak benim cevabımdaki cevap. Mükemmel detay ve sunum!
drxzcl

@Iain: Hayır burada doğru ya da yanlış yoktur. Her ne kadar yönteminizin iki ayrı durumu olacağını tahmin etsem de: hızlanma / yavaşlama, bu yöntem kontrol teorisinden bir regülatörden esinlenerek, aşınmayı ve salınımları azaltırken hızlı bir yanıt vermek için ivmeyi ölçeklendiriyor.
Staffan E

1
Diğer yorumlarda olduğu gibi, bu, sabit bir hedef için çalışacak, ancak herhangi bir hareketli hedef için kabul edilemez olacaktır. C0 ve C1 terimleri, geleneksel sönümlü yay malzemeleridir; burada C0, yayın kuvvetini (genellikle denir k) temsil eder ve C1, sönümleme faktörüdür (genellikle 'B' veya 'c' olarak adlandırılır). Bu yüzden evet, sönümlendirmeyi yukarı kaldırarak salınımı en aza indirgeyebilirsiniz ancak sorun, bunun hedefin nerede olacağını tahmin etmemesidir , bu yüzden istenen hedefi gecikmeye mahkumdur.
Dash-Tom-Bang

3

Burada sahip olduğunuz temel bir kontrol sorunudur . Taret sistem, hızlanma kontrol ve sensör konum / hız ölçer. Mühendislikte çok iyi çalışılmış bir problem olduğu için, bu problemlerin üstesinden gelmenin birçok yolu vardır.

Anahtar kararlı bir sistem, yani salınım üretmeyen bir sistemle bitiyor. Bu genellikle sönümleme eklenerek yapılır. Wikipedia sayfası sizi başlatmalıdır.


2

İlk önce, taretten hedefe vektörü hesaplayın. O zaman bunu taretin mevcut vektörüyle karşılaştırın. Ardından, taretin belirli bir süre içinde doğru yöne dönmesi için gereken açısal ivmeyi ve açısal hızı bulmak için ikisi arasındaki farkı kullanın.

Tamam, bu basit görünüyordu. Bununla birlikte, hedefin pozisyonunu önceden tahmin etmeye çalışmalısınız çünkü hedef tareti çevirdiğiniz zaman hareket edecektir. Bunu yapmak için:-

Pd' = Pd + t.Vd
Ps' = Ps + t.Vs

burada P konum ve V hız ve alt simge hedef (hedef) için d ve kaynak (taret) için s'dir, bu bir yön vektörü verir: -

Dsd' = Pd' - Ps' = Pd + t.Vd - (Ps + t.Vs) = Pd - Ps + (Vd - Vs).t

burada D bir yön vektörüdür ve Dsd 't zamanında gereken yöndür. Şimdi, mevcut pozisyona ve belirli bir süre için maksimum hıza ve ivmeye dayalı taretin yönünü hesaplayın: -

Ds' = t.Ds.Rs -> this is a vector rotation

Ds ve Ds 'kaynak yönleridir ve Rs dönme hızıdır. Bütün bunlarla, ne zaman Dsd '== Ds' ve böylece Rs, gereken dönme hızını bulmak istersiniz. Tüm P'lerin, D'lerin ve V'lerin x ve y bileşenlerine sahip olduğunu unutmayın.

Burada ivmeyi hesaba katmadım - bu karmaşıklığa çok daha fazla katkıda bulunuyor. Bir kez Rs ve t elde ettikten sonra, aynı sonucu elde etmek için muhtemelen bir parabolik Rs (yani hızlandırın ve yavaşlatın) olarak tahmin edebilirsiniz.


Bu, durdurma hesaplaması için iyi bir cevap gibi gözüküyor, ancak ne yazık ki, bu tür matematik gösterimini okuyan ve program koduna çeviren ve cevabı bilmeyen oyunları yapan insanların arasında büyük bir boşluk var. soru. Diğer bir deyişle, oyunun bu matematik gösterimini okuyabilecek dev geliştiriciler olduğunu düşünüyorum, muhtemelen zaten ateşleme çözümünün nasıl programlanacağını çözebilir. Terimlerinizin ne anlama geldiğini açıklarsanız, formüllerinizi anlamama yardımcı olur.
Dronz


0

Yapılacak ilk şey, akımla izlenen nesne arasındaki açıyı hesaplamaktır.
Bir sonraki şey geçerli torrent hızını kullanarak ve maksimum ivmeyi geriye doğru uygulamak (torrenti durdurmak) torrentin izlenen nesneden önce mi sonra mı durduğunu kontrol etmektir.
Cevap, torrentin izlenen nesneden önce duracak olması durumunda, ileri doğru maksimum ivmeyi uygulayın (artan hız).
Cevap, torrentin izlenen nesneden sonra duracak olması durumunda, maksimum ivmeyi geriye doğru uygulayın (torrenti durdurun).
Bu şekilde torrent en hızlı şekilde ulaşır ve doğru noktada durur (veya daha sonra bir bölüm).

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.