Çerçeveden Bağımsız Hareket


11

Burada hareketle ilgili iki konu daha okudum: Zamana dayalı hareket Vs Kare hızına dayalı hareket? ve Ne zaman sabit veya değişken bir zaman adımı kullanmalıyım?

fakat bence çerçeve bağımsız hareketinin temel bir anlayışından yoksunum çünkü o konuların ne hakkında konuştuğunu anlamıyorum.

Ben lazyfoo SDL öğreticiler ile birlikte takip ve çerçeve bağımsız ders geldi. http://lazyfoo.net/SDL_tutorials/lesson32/index.php

Kodun hareket kısmının ne söylemeye çalıştığından emin değilim ama bence bu (yanlışsam lütfen beni düzelt): Çerçeve bağımsız hareketine sahip olmak için, bir nesnenin ne kadar uzak olduğunu bulmamız gerekir ( örn. hareketli grafik) belirli bir zaman dilimi içinde hareket eder, örneğin 1 saniye. Nokta saniyede 200 piksel hareket ederse, o zaman 200 pps saniyenin 1 / 1000'i ile çarparak o saniye içinde ne kadar hareket ettiğini hesaplamam gerekir.

Bu doğru mu? Ders diyor ki:

"saniye başına piksel cinsinden hız * saniye olarak son kareden bu yana geçen süre. Program saniyede 200 kare hızında çalışıyorsa: 200 pps * 1/200 saniye = 1 piksel"

Ama ... Sanırım 200 pps saniyenin 1 / 1000'i ile çarpıyoruz. Saniyede kare olan bu iş nedir?

Birinin bana çerçeve bağımsız hareketin nasıl çalıştığı hakkında biraz daha ayrıntılı bir açıklama yapıp yapamayacağını takdir ediyorum.

Teşekkür ederim.

İLAVE:

SDL_Rect posRect;
posRect.x = 0;
posRect.y = 0;

float y, yVel;
y = 0;
yVel = 0;

Uint32 startTicks = SDL_GetTicks();

bool quit = false;
SDL_Event gEvent;

while ( quit == false )
{
    while ( SDL_PollEvent( &gEvent ) )
    {
        if ( gEvent.type == SDL_QUIT )
            quit = true;
    }

    if ( y <= 580 )
    {
        yVel += DOT_VEL;
        y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
        posRect.y = (int)y;
    }

    startTicks = SDL_GetTicks();
    SDL_BlitSurface( bg, NULL, screen, NULL );
    SDL_BlitSurface( dot, NULL, screen, &posRect );
    SDL_Flip( screen );
}

Ekranda bir noktayı hareket ettiren kod budur. Sanırım şimdiye kadar her şeyim doğru. Ekranda aşağı doğru hareket eder, ancak açıklayamadığım biraz garip bir şey var. Nokta, o y değerinden daha büyük bir değere ulaştığında y = 580'de kalmalıdır. Ancak, programı her çalıştırdığımda, nokta farklı bir konuma gelecek, yani 580'den biraz daha fazla, yani nokta ekranın yarısında veya yarısından daha fazla olacak (nokta 20 piksel, ekran boyutlar 800x600). Programın başlık çubuğunu tıklayıp basılı tutup serbest bırakma gibi bir şey yaparsam, nokta ekrandan kaybolur. Her seferinde nasıl değişken oluyor? Başlık çubuğu sorununa gelince, bunun nedeni başlık çubuğuna tuttuğumda, zamanlayıcı hala çalışıyor ve geçen süre büyüyor, daha büyük bir mesafeyle sonuçlanır ve nokta bir sonraki çerçevede hareket eder. Bu doğru mu?


Eklemeniz aslında başka bir soru. Mevcut sorunuza eklemek yerine ikinci bir soru yapmanız gerekir. Yine de kolayca cevaplanabilir: Sadece y hareketini hesaplayın, örn. yMovement = (yVel * (SDL_GetTicks() - startTicks)/1000.f);sonra yapın:if(y + yMovement <= 580){ y += yMovement; } else { y = 580; }
bummzack

Yanıtlar:


10

NOT: Tüm kesirlerin float olması amaçlanmıştır.

Çerçeve bağımsız hareket, hareketi zamanın dışına dayandırarak çalışır. Son kareden bu yana harcanan süreyi alırsınız (bu nedenle bir saniyede 60 kare varsa, tüm kareler aynı miktarda zaman aldıysa her kare 1.0 / 60.0 saniye sürer) ve çevirir.

Varlığınızın belirli bir süre boyunca belirli bir miktarda alanı hareket ettirmesini istiyorsanız (her saniye için 100 piksel diyelim), o zaman başına hareket miktarını çarparak kare başına kaç piksel hareket etmeniz gerektiğini öğrenebilirsiniz. Geçerli karede ne kadar hareketin gerçekleşmesi gerektiğini anlamak için saniye (1.0 / 60.0) olarak geçen süreye (100/100 piksel) kadar.

Geçen zaman miktarını ve belirli bir zaman birimi ile tanımlanan bir hızı (saniye veya milisaniye tercih edilir) kullanarak kare başına ne kadar hareket yapmanız gerektiğini anlayarak çalışır. Yani hesaplamanız şöyle görünebilir:movementPerSecond * (timeElapsedInMilliseconds / 1000.0)

Umarım bu sizin için bir anlam ifade eder.

Adamımı her saniye 200 piksel sağa taşımak istiyorum. Geçerli kare bir önceki kareden sonra 50 milisaniye çalıştırılırsa, adamımı daha önce belirtilen hızın (200 piksel) bir kısmını hareket ettirmeliyim. Ona mesafenin 50 / 1000'ini hareket ettirmeliyim çünkü sadece 1 / 20'inci (50/1000 = 1/20) zaman geçti. Bu nedenle onu sadece 10 piksel hareket ettirmek mantıklı olacaktır (19 kare daha oluşursa, birbirinden 50 milisaniye ayrı, o saniyedeki toplam hareket miktarı 200 piksel, istediğimiz miktar).

Çerçeveden bağımsız hareketin çalışma şekli, çerçevelerin genellikle değişken zaman adımlarında meydana gelmesidir (sonraki kareler arasında farklı bir süre vardır). Bir objeyi sürekli olarak her karede sabit bir mesafeye taşırsak, hareket kare hızına dayanır. Çerçeveler arasında çok fazla zaman varsa, oyun çok yavaş hareket edecek gibi görünecek ve çerçeveler arasında çok fazla zaman yoksa, oyun hızlı gidiyor gibi görünecektir. (kareler arasında çok az zaman = çok fazla kare = daha fazla hareket) Bunun üstesinden gelmek için, zaman açısından bir hız kullanırız ve kareler arasındaki süreyi izleriz. Bu şekilde pozisyonu en son güncellediğimizden bu yana ne kadar zaman geçtiğini ve varlığı ne kadar ileriye taşımamız gerektiğini biliriz.

Saniyedeki kare sayısı: Bu, saniyede gerçekleşen kare sayısıdır. Genellikle kare hızı, oyunun saniyede kaç kez çizildiği / oluşturulduğu veya saniyede kaç kez oyun döngüsünün tamamlandığıdır.

Sabit Ayet Değişken Zaman Adımı: Bu, kareler arasındaki zaman miktarını ifade eder. Genellikle, çerçeveler arasındaki süre sabit olmaz. Fizik gibi bazı sistemlerin / çekirdeklerin bir şeyi simüle etmek / çalıştırmak için bir miktar zamana ihtiyacı olacaktır. Zaman aşaması sabitse, genellikle fizik sistemleri daha kararlı / ölçeklenebilirdir. Sabit / değişken zaman adımları arasındaki fark isimlerdedir. Sabit zaman adımları, kulağa şu şekilde gelir: sabit bir zamanda meydana gelen zaman adımları. Değişken zaman adımları, değişen / farklı zaman oranlarında meydana gelen zaman adımlarıdır.


Verdiğiniz örnekte, her karenin süresi 50 milisaniye, doğru mu? Ve bu 1000 / FPS ile mi hesaplandı? Ve böylece her kareyi yapmanız gereken hareket saniyede pikseldir * 50/1000?
KaridesCrackers

hm, her zaman çerçevesi için milisaniyenin büyük olasılıkla değişken olacağını fark ettim, değil mi? GetTicks () gibi bir şey - startTicks her zaman farklı olur ve sabit olmaz.
KaridesCrackers

@Omnion: "Saniyede piksel" cinsinden mesafeyi belirtirseniz milisaniye kullanamazsınız ... 1000/60 değil 1.0 / 60.0 olmalıdır, bu tamamen farklı bir şeyle sonuçlanır.
bummzack

@ShrimpCrackers evet, geçen zaman değişir. 60 fps işleme kapasitesine sahip olmayan daha eski bir PC düşünün. Yine de oyunun böyle bir makinede aynı hızda (ancak aynı fps'de değil) çalışmasını istiyorsunuz.
bummzack

peki lazyfoo eğitiminde 1000 deltaticks / 1000.f'de ne anlama geliyor? FPS? 1000 milisaniye? Şu an biraz kafam karıştı. Her kare için gereken sürenin belirlenmesinde FPS'nin gerekli olduğu, ancak aslında hareketin içinde hesaplanmadığı anlaşılıyor.
KaridesCrackers

7

Çerçeve dinamiğinde, bir objeyi taşımak için (örneğin) kodunuz şöyle görünür:

x = x + speedPerFrame

Çerçeveden bağımsız olmak istiyorsanız, şöyle görünebilir:

x = x + speedPerSecond * secondsElapsedSinceLastFrame

teşekkürler, bu mantıklı. Yukarıda başka bir sorum daha var.
KaridesCrackers

1

Ek soru ile ilgili.

Noktanız her seferinde farklı konumlarda durur, çünkü taşıdığınızda sınırı (y> 580) kontrol etmezsiniz. Güncellemeyi yalnızca geçmiş 580 bir kez daha durdurursunuz.

580'i geçmeden önceki son karede 579'dan başlıyor olabilirsiniz veya 570'de olabilirsiniz veya 100'de olabilirsiniz.

IF koşulunuzu böyle bir şeye değiştirin ve iyi olmalısınız.

if ( y <= 580 )
{
    yVel += DOT_VEL;
    y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
    if( y > 580 )
    {
        y = 580;
    }
    posRect.y = (int)y;
}
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.