Ekstrapolasyon, çarpışma algılamasını bozar


10

Sprite'ımın hareketine ekstrapolasyon uygulamadan önce, çarpışmam mükemmel bir şekilde çalıştı. Ancak, sprite hareketime ekstrapolasyon uyguladıktan sonra (işleri düzeltmek için), çarpışma artık çalışmıyor.

Ekstrapolasyondan önce işler şu şekilde işler:

resim açıklamasını buraya girin

Ancak, benim ekstrapolasyonumu uyguladıktan sonra, çarpışma rutini kırılıyor. Bunun, dışkılama rutini (benim render çağrımda bulunan) tarafından üretilen yeni koordinat üzerinde hareket ettiği için varsayıyorum.

Ekstrapolasyonumu uyguladıktan sonra

resim açıklamasını buraya girin

Bu davranış nasıl düzeltilir?

Ekstrapolasyondan hemen sonra ekstra bir çarpışma kontrolü yapmayı denedim - bu birçok problemi ortadan kaldırıyor gibi görünüyor, ancak bunu dışladım çünkü renderımıza mantık koymak söz konusu değil.

Ben de spritesX pozisyonunun bir kopyasını yapmayı denedim, bunu tahmin edip orijinalden ziyade kullanarak çizim yaptım, böylece orijinali mantığın ele geçirmesi için sağlam bıraktım - bu daha iyi bir seçenek gibi görünüyor, ancak yine de bazı garip efektler üretiyor duvarlarla çarpışırken. Bunun da bununla başa çıkmanın doğru yolu olmadığından eminim.

Burada birkaç benzer soru buldum ama cevapları bana yardımcı olmadı.

Bu benim ekstrapolasyon kodum:

public void onDrawFrame(GL10 gl) {


        //Set/Re-set loop back to 0 to start counting again
        loops=0;

        while(System.currentTimeMillis() > nextGameTick && loops < maxFrameskip){

        SceneManager.getInstance().getCurrentScene().updateLogic();
        nextGameTick+=skipTicks;
        timeCorrection += (1000d/ticksPerSecond) % 1;
        nextGameTick+=timeCorrection;
        timeCorrection %=1;
        loops++;
        tics++;

     }

        extrapolation = (float)(System.currentTimeMillis() + skipTicks - nextGameTick) / (float)skipTicks; 

        render(extrapolation);
}

Ekstrapolasyon uygulama

            render(float extrapolation){

            //This example shows extrapolation for X axis only.  Y position (spriteScreenY is assumed to be valid)
            extrapolatedPosX = spriteGridX+(SpriteXVelocity*dt)*extrapolation;
            spriteScreenPosX = extrapolationPosX * screenWidth;

            drawSprite(spriteScreenX, spriteScreenY);           


        }

Düzenle

Yukarıda bahsettiğim gibi, sprite koordinatlarının bir kopyasını özellikle çizmek için denedim .... Bu kendi problemleri var.

İlk olarak, kopyalamaya bakılmaksızın, hareketli grafik hareket ederken, süper yumuşaktır, durduğunda, biraz sola / sağa sallanıyor - hala zamana göre konumunu tahmin ediyor. Bu normal bir davranış mı ve hareketli grafik durduğunda 'kapatabilir miyiz?

Sol / sağ için bayraklara sahip olmayı denedim ve sadece bunlardan biri etkinse ekstrapolasyon. Ayrıca, herhangi bir fark olup olmadığını görmek için son ve mevcut konumları kopyalamayı denedim. Ancak, çarpışmaya gelince, bunlar yardımcı olmuyor.

Kullanıcı söyle tuşuna basarsa, sağ düğme ve hareketli grafik sağa doğru hareket ediyorsa, bir duvara çarptığında, kullanıcı sağ düğmeyi basılı tutmaya devam ederse hareketli hareketli duvar tarafından durdurulurken hareketli çizgi sağa doğru hareket edecektir ( bu yüzden aslında hareket etmiyor), ancak doğru bayrak hala ayarlandığından ve ayrıca çarpışma rutini hareketli grafiği duvardan sürekli hareket ettirdiği için, hareketli grafiğin hala hareket ettiği kodda (oyuncu değil) görünür ve bu nedenle ekstrapolasyon devam ediyor. Yani oyuncunun göreceği şey, hareketli 'statik' (evet, canlandırıyor, ama aslında ekran boyunca hareket etmiyor) ve her zaman ve sonra ekstrapolasyon bir şey yapmaya çalıştıkça şiddetle sallanıyor ..... .. Umarım bu yardım


1
Tam olarak anlamak için bu bazı sindirerek alacaktır ( 'enterpolasyon' görünüşte bir düzine farklı anlamlara sahiptir ve burada onun tarafından sadece ne demek ilk bakışta tamamen net değil) ama benim ilk içgüdüsü yaptığınızı olmamalıdır' dir şeyi etkileyecek senin nesnenin oluşturma rutininizdeki konumu '. Oluşturucunuz nesneyi nesnenin verilen konumuna çizmeli ve nesneyi manipüle etmek için sorun için bir reçete var, çünkü oluşturucuyu doğal olarak oyunun fiziğine bağlar. İdeal bir dünyada, oluşturucunuz oyun nesnelerine sabit işaretler alabilmelidir.
Steven Stadnicki

Merhaba @StevenStadnicki, çok teşekkürler Yorumlarınız için, Oluşturucu içine geçirilen bir interpolasyon değerini gösteren örnekler çok sayıda var, bu bakın: mysecretroom.com/www/programming-and-software/... ben uyarlanan yerden is my kodu. Benim sınırlı anlayışım, son güncellemeden bu yana geçen süreye bağlı olarak son ve sonraki güncellemeler arasındaki konumu enterpolasyonlu hale getirmesidir - bunun bir kabus olduğunu kabul ediyorum! Eğer daha kolay çalışmak için önermek ve alternatif eğer minnettar olurum - şerefe :-)
BungleBonce

6
'Sadece bir şeyin kodunu bulabilmeniz en iyi uygulama olmadığı için' diyeceğim. :-) Bu durumda, yine de, bağlandığınız sayfanın nesnelerinin nerede görüntüleneceğini bulmak için enterpolasyon değerini kullandığından şüpheleniyorum , ancak aslında nesne konumlarını onlarla güncellemiyor; bunu, her kareyi hesaplayan çizime özgü bir konuma sahip olarak, ancak bu konumu nesnenin gerçek 'fiziksel' konumundan ayrı tutarak da yapabilirsiniz.
Steven Stadnicki

Merhaba @StevenStadnicki, sorumun ana hatlarıyla belirtildiği gibi ("Ben de bir kopya yapmayı denedim" başlangıcı paragraf), aslında bir 'sadece beraberlik' pozisyonu kullanmaya çalıştım :-) Ben nerede interpolasyon yöntemi önerebilir miyim render rutini içinde hareketli grafiğin konumunda ayarlamalar yapmanıza gerek yok mu? Teşekkürler!
BungleBonce

Kodunuza baktığınız zaman, enterpolasyon yerine ekstrapolasyon yaptığınız anlaşılıyor.
Durza007

Yanıtlar:


1

Henüz bir yorum gönderemiyorum, bu yüzden bunu bir cevap olarak göndereceğim.

Sorunu doğru anlarsam, böyle bir şey gider:

  1. önce bir çarpışmanız var
  2. nesnenin konumu düzeltilir (muhtemelen çarpışma algılama rutini tarafından)
  3. nesnenin güncellenmiş konumu oluşturma işlevine gönderilir
  4. oluşturma işlevi daha sonra ekstrapolasyon kullanarak nesnenin konumunu günceller
  5. ekstrapole edilmiş nesnenin pozisyonu şimdi çarpışma tespit rutinini kırıyor

3 olası çözümü düşünebilirim. Onları en az IMHO'ya en çok arzu edilen sırada listeleyeceğim.

  1. Ekstrapolasyonu oluşturma işlevinin dışına taşıyın. Nesnenin konumunu tahmin edin ve ardından bir çarpışma olup olmadığını test edin.
  2. ya da ekstrapolasyonu render fonksiyonunda tutmak istiyorsanız, bir çarpışma olduğunu göstermek için bir bayrak ayarlayın. Çarpışma algılamanın nesnenin konumunu zaten yaptığınız gibi düzeltmesini sağlayın, ancak ekstrapolasyon değerini hesaplamadan önce çarpışma bayrağını kontrol edin. Nesne zaten olması gereken yerde olduğundan, taşınmasına gerek yoktur.
  3. Benim için bir çözümden daha fazla çözüm olan son olasılık, çarpışma algılamasını aşırı derecede telafi etmek olacaktır. Bir çarpışmadan sonra, nesneyi duvardan uzağa hareket ettirin, böylece ekstrapolasyondan sonra nesne duvara geri döner.

# 2 için örnek kod.

if (collisionHasOccured)
    extrpolation = 0.0f;
else
    extrapolation = (float)(System.currentTimeMillis() + skipTicks - nextGameTick) / (float)skipTicks;

# 2 muhtemelen daha hızlı ve kolay bir koşu olabilir, ancak # 1 daha mantıklı bir çözüm gibi görünüyor. Delta zamanı çözümünüzü nasıl ele aldığınıza bağlı olarak # 1, büyük bir delta ile aynı şekilde kırılabilir, bu durumda hem # 1 hem de # 2'yi birlikte kullanmanız gerekebilir.

EDIT: Kodunuzu daha önce yanlış anladım. Döngüler mümkün olduğunca hızlı oluşturulmalı ve belirli bir aralıkta güncellenmelidir. Bu nedenle, çizim yaptığınız durumun güncellenmekten daha fazlasını ele almak için hareketli grafik konumunu enterpolasyonluyorsunuz. Ancak, döngü geride kalırsa, yakalanana veya maksimum kare çekilişi atlanana kadar güncelleme konusunda anket yaparsınız.

Bununla birlikte, tek sorun nesnenin bir çarpışmadan sonra hareket etmesidir. Bir çarpışma olursa, nesne bu yönde hareket etmeyi bırakmalıdır. Dolayısıyla, bir çarpışma varsa, hızı 0 olarak ayarlayın. Bu, oluşturma işlevinin nesneyi daha fazla hareket ettirmesini durdurmalıdır.


Merhaba @Aholio Seçenek 2 denedim ve işe yarıyor ama birkaç aksaklık neden olabilir belki yanlış yaptım, ben tekrar. Bununla birlikte, bunun nasıl yapılacağı hakkında hiçbir bilgi bulamadığım halde seçenek 1 ile çok ilgileniyorum. Mantık rutinimde nasıl söyleyebilirim? BTW benim deltam sabittir 1/60 veya 0.01667'dir (bunun yerine, entegre etmek için kullandığım rakam budur, ancak oyunumun her yinelemesinin süresi ne olduğuna bağlı olarak açıkça değişebilir, ancak asla gerçekte 0.01667'den fazla almamalıdır. ) bu konuda herhangi bir yardım çok teşekkür ederim.
BungleBonce

Belki ne yaptığınızı tam olarak anlamıyorum. Bana biraz garip gelen bir şey sadece çizim fonksiyonunuzda pozisyon hareketleri yapmak değil; ayrıca zaman hesaplamaları yapıyorsunuz. Bu her nesne için mi yapılıyor? Doğru sıra: oyun döngü kodunda yapılan zaman hesaplaması olmalıdır. Oyun döngüsü deltayı bir güncelleme (dt) işlevine geçirir. Güncelleme (dt) tüm oyun nesnelerini güncelleyecektir. Herhangi bir hareket, ekstrapolasyon ve çarpışma algılamasını ele almalıdır. Update () oyun döngüsüne döndükten sonra, yeni güncellenen tüm oyun nesnelerini çizen bir render () işlevini çağırır.
Aholio

Hmmmmm şu anda güncelleme fonksiyonum her şeyi yapıyor. Hareket (hareketle demek istediğim, spriteların yeni konumunu hesaplar - bu benim delta zamanımdan hesaplanır). Oluşturma fonksiyonumda yaptığım tek şey (aslında çizim dışında) 'yeni' pozisyonunu tahmin etmek, ancak elbette bu, son mantık güncellemesinden render çağrısına kadar geçen zamanı hesaba katmak zorunda olduğu için zamanı kullanıyor. Bu benim anlayışım zaten :-) Bunu nasıl yapardın? Sadece mantık güncellemesinde ekstrapolasyonun nasıl kullanılacağını anlamıyorum. Teşekkürler!
BungleBonce

Cevabım güncellendi. Umut yardımcı olur
Aholio

Teşekkürler, orijinal Q'uma bakın "durduğunda hafifçe sola / sağa sallanıyor" - bu yüzden sprite'ımı durdursam bile, ekstrapolasyon hala sprite 'hareketli' (wobbling) 'i koruyor - çünkü bu kullanmıyorum sprite'ın ekstrapolasyonumu çözmek için eski ve mevcut pozisyonları, bu nedenle sprite statik olsa bile, her kare yinelemesinde çalışılan 'ekstrapolasyon' değerine dayanan bu sallanma etkisine hala sahiptir. Hatta 'eski ve şimdiki pos aynıysa o zaman tahmin etmeyin' demeyi denedim ama bu hala işe yaramıyor gibi görünüyor, geri dönüp yine de başka bir göz atacağım!
BungleBonce

0

Fizik oluşturma ve güncelleme işlemlerini tamamen ayırmanız gerektiği anlaşılıyor. Genellikle altta yatan simülasyon ayrık zaman adımlarında çalışır ve frekans asla değişmez. Örneğin, topunuzun hareketini saniyenin 1/60. Saniyesinde simüle edebilirsiniz ve hepsi bu kadar.

Değişken kare hızına izin vermek için, oluşturma kodu değişken bir frekansta çalışmalıdır, ancak herhangi bir simülasyon yine de sabit bir zaman adımında olmalıdır. Bu, grafiklerin simülasyondaki belleği salt okunur olarak okumasını ve ekstrapolasyon yerine enterpolasyonu ayarlamanıza olanak tanır.

Ekstrapolasyon gelecekteki değerlerin nerede olacağını tahmin etmeye çalıştığından, hareketteki ani değişiklikler size büyük ekstrapolasyon hataları verebilir. Bunun yerine sahnenizi simülasyonun ardındaki bir çerçeve hakkında oluşturmak ve bilinen farklı pozisyonlar arasında enterpolasyon yapmak daha iyidir.

Uygulamanın bazı ayrıntılarını görmek istiyorsanız, buradaki bir makalede bu konu hakkında kısa bir bölüm zaten yazdım . Lütfen "Timestepping" adlı bölüme bakın.

Makaleden çıkan önemli psuedo kodu:

const float fps = 100
const float dt = 1 / fps
float accumulator = 0

// In units seconds
float frameStart = GetCurrentTime( )

// main loop
while(true)
  const float currentTime = GetCurrentTime( )

  // Store the time elapsed since the last frame began
  accumulator += currentTime - frameStart( )

  // Record the starting of this frame
  frameStart = currentTime

  // Avoid spiral of death and clamp dt, thus clamping
  // how many times the UpdatePhysics can be called in
  // a single game loop.
  if(accumulator > 0.2f)
    accumulator = 0.2f

  while(accumulator > dt)
    UpdatePhysics( dt )
    accumulator -= dt

  const float alpha = accumulator / dt;

  RenderGame( alpha )

void RenderGame( float alpha )
  for shape in game do
    // calculate an interpolated transform for rendering
    Transform i = shape.previous * alpha + shape.current * (1.0f - alpha)
    shape.previous = shape.current
    shape.Render( i )

RenderGameFonksiyon en ilgi olduğunu. Fikir, ayrık simülasyon konumları arasında enterpolasyon kullanmaktır. Oluşturma kodu, simülasyon salt okunur verilerinin kendi kopyalarını yapabilir ve oluşturmak için geçici enterpolasyonlu bir değer kullanabilir. Bu, sahip olduğunuz gibi aptalca sorunlar olmadan size çok düzgün bir hareket verecektir!

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.