2015-12-14 33 views
6

Pekala, bu konuyla ilgili bazı araştırmalar yaptım ve sorunu çözdüğümde bulduğum çözümlerin çoğunu araştırdım, ancak bunların doğru çalışmadığını düşünüyorum. Ben sadece basit bir küçük parçacık motorunun uygulanmasının ilk aşamalarındayım, çılgınca bir şey değil, sadece can sıkıntımdan yapıyorum. Daha önce WinForms ile böyle bir şey yapmadım, C/C++ ile kesinlikle var ama bu benim için yeni bir şey. Aşağıdaki parçacıklar ekrana parçacıklar çizmek için kullanıyorum kod, parçacıklar için kazan plaka kodu iyi çalışıyor gibi uygun değil, benim gerçek oyun döngüsü hakkında daha fazla merak ediyorum. İşte Ekranda C# WinForms programında titreme temizle

güncellemeler için ana kod ve ben içine çalıştırıyorum sorun ekran temizlenir ve güncellendiğini zaman olduğu

public MainWindow() 
    { 
     this.DoubleBuffered = true; 
     InitializeComponent(); 
     Application.Idle += HandleApplicationIdle; 
    } 

    void HandleApplicationIdle(object sender, EventArgs e) 
    { 
     Graphics g = CreateGraphics(); 

     while (IsApplicationIdle()) 
     { 
      UpdateParticles(); 
      RenderParticles(g); 
      g.Dispose(); 
     } 
    } 

    //Variables for drawing the particle 
    Pen pen = new Pen(Color.Black, 5); 
    Brush brush = new SolidBrush(Color.Blue); 
    public bool emmiter = false; 

    private void EmitterBtn_Click(object sender, EventArgs e) 
    { 
     //Determine which emitter to use 
     if (emmiter == true) 
     { 
      //Creates a new particle 
      Particle particle = new Particle(EmitterOne.Left, EmitterOne.Top, .5f, .5f, 20, 20); 
      emmiter = false; 
     } 
     else if(emmiter == false) 
     { 
      Particle particle = new Particle(EmitterTwo.Left, EmitterTwo.Top, -.5f, .5f, 20, 20); 
      emmiter = true; 
     } 
    } 

    public void RenderParticles(Graphics renderer) 
    { 


     Invalidate(); 
     Thread.Sleep(0); 

     //Iterate though the static list of particles 
     for (int i = 0; i < Particle.activeParticles.Count; i++) 
     { 


      //Draw Particles 
      renderer.DrawRectangle(pen, Particle.activeParticles[i].x, 
           Particle.activeParticles[i].y, 
           Particle.activeParticles[i].w, 
           Particle.activeParticles[i].h); 
     } 
    } 

    public void UpdateParticles() 
    { 
     for (int i = 0; i < Particle.activeParticles.Count; i++) 
     { 
      //Move particles 
      Particle.activeParticles[i].MoveParticle(); 
     } 
    } 

, bu korkunç titremeyi alır yeniden çizer ve sadece bu değil ama bazen Bir parçacığı her yaydığımda olmaz.

Form, temel olarak, etiketleri yalnızca her parçacığın nerede oluşturulacağını söylemek için ekranda görünmeyen konumlar olarak kullanıyor.

Her neyse, bu konuyu daha önce görmüştüm ama hiçbir şey herhangi bir şeyi sabitlememiş, mevcut uygulama en az titreme/laggy'tir ancak sorunu çözmüyor.

Herhangi bir yardım için teşekkür ederiz, teşekkürler!

EDIT * Grafik nesnesinin her bir döngüden hiçbir zaman ayrılmamış olduğumu fark ettim, böylece bunu yaptığımda ve yayıcı düğmesini tıklattığımda daha fazla gecikme olmamasına rağmen, titreşim hala var, kodu buna göre güncelleştirdim.

+0

'Invalidate();' tüm kontrol alanının silinip silinmesine ve dolayısıyla titreşime neden olur. Normalde biri bir ekran önbellekine çekilecekti, ancak sadece nokta çiziyorsanız, eski nokta konumlarını hatırlayabilir ve yeni konumu çizmeden önce bunları silebilirsiniz. Bir noktaya çalışır. Söylediğim gibi offscreen buffer tercih edilir. Animasyonunuzun hızı, "Application.Idle" öğesine göre kötü bir şekilde dalgalanacaktır. Bir zamanlayıcı kullanmayı düşünebilirsiniz. – MickyD

+0

İlginç, okuduğum diğer şeyler, aynı şeyi düşünmeme rağmen zamanlayıcının güvenilir olmadığını söylüyor, bunu denemeliyim. –

+0

"System.Windows.Forms.Timer", özellikle de 30 FPS'yi hedeflemek istiyorsanız, bu tür şeyler için iyidir.'Zamanlayıcı', bunun üstesinden gelmek için yeterli derstir (süper hassas bir zamanlayıcısından sonra değiliz). Bir zamanlayıcı yerine uygulama boşta oturmuş olması sorunu, eğer fare hakkında hareket ederseniz, Windows sizin C++ MFC günlerinde gördüğünüz ve muhtemelen C# 'da takip ettiğimiz uygulama rölanti mesajlarının miktarını azaltacaktır. :) – MickyD

cevap

5

Görünür boya kalıntılarından kurtulmak için çift arabelleğe alma gerekir. Başka bir deyişle, sahneyi hazır olduğunda, tek bir adımda ekran yüzeyine hızla karışan bir arka tampona dönüştürün. Winforms içinde yerleşik bir özellik, sadece DoubleBuffered özelliğini form kurucusunda true olarak ayarlayın. , bundan yararlanmak için Paint etkinliğini kullanmalıdır. OnPaint() öğesini geçersiz kılın ve RenderParticles (e.Graphics) öğesini çağırın.

Zamanlama ile ilgilenmeniz gerekiyor, şu anda kullanıcı arabiriminiz% 100 çekirdek ve animasyon hızında yanıyor, parçacıkların sayısına ve makinenin hızına bağlıdır. Application.Idle yerine, bir Timer'ı araç kutusundan formunuza bırakın. Tick ​​olay işleyicisinde, Paint olayının yeniden tetiklenmesini sağlamak için UpdateParticles() ve this.Invalidate() öğesini çağırın. Zamanlayıcının Interval özellik değeri kritiktir, 15 veya 31 milisaniye (64 veya 32 FPS) seçerek en çok tekrarlanabilen güncelleme oranı elde edersiniz.

İstediğiniz FPS oranını her zaman alamazsınız, makine meşgulse veya çok yavaşsa veya UI iş parçacığının çalıştırması gereken başka bir kod varsa, zamanlayıcı basitçe bir Tick olayını geciktirir veya atlar. Animasyonu etkilemediğinden emin olmak için, parçacıkları sabit bir miktarda hareket ettirmek yerine gerçek geçen süreyi ölçmelisiniz. Environment.TickCount, DateTime.UtcNow veya Stopwatch, gerçek geçen süreyi ölçmenin uygun yoludur.