2016-11-28 2 views
0

Je suis actuellement en train de créer un moteur de jeu 2D utilisant C#, GDI et j'ai configuré un simple cadre. Le jeu ne peut que rendre 60fps. Pour autant que je sache, il n'y a pas de problème avec le code, je voudrais juste une façon plus propre de rendre 60fps et pas plus.Boucle de jeu C# GDI (compteur FPS)

Voici mon code, toute aide serait grande

 public void Run() 
    { 
     window.Show(); 
     window.Focus(); 

     Initialize(); 

     isRunning = true; 
     canRender = true; 

     timer = new Stopwatch(); 
     timer.Start(); 

     // the amount of milliseconds needed to pass before rendering next frame 
     double frameCapCounter = 16.666666; 

     while (isRunning) 
     { 
      Application.DoEvents(); 

      if (window.Focused) 
      { 
       if (timer.ElapsedMilliseconds >= frameCapCounter) 
       { 
        canRender = true; 
        frames += 1; // update amount of frames 
        frameCapCounter += 16.666666; // increment counter 
       } 
       else 
       { 
        canRender = false; 
       } 

       // this is used to check if a second has passed, and if so 
       // we set the fps variable to the amount of frames rendered 
       // and reset all variables. 
       if (timer.ElapsedMilliseconds >= 1000) 
       { 
        fps = frames; 
        frames = 0; 
        frameCapCounter = 0; 
        timer.Restart(); 
       } 

       Update(); 
       LateUpdate(); 

       if (canRender) 
        Render(); 
       else 
       { 
        Thread.Sleep(1); 
       } 
      } 
     } 
    } 
+0

Les gars de SlimDX (https://slimdx.org/docs/html/Managed_Message_Loop.htm) l'ont utilisé au lieu de 'Application.DoEvents()': https://blogs.msdn.microsoft.com/tmiller/ 2005/05/05/mon-dernier-post-sur-rendre-boucles-espérons-le / –

Répondre

0

Dans votre scénario, au lieu de garder une trace du temps écoulé, les images rendues, etc., etc., vous pouvez simplement dormir le nombre de millisecondes à plafonner votre FPS, par exemple:

public void Run() 
{ 
    window.Show(); 
    window.Focus(); 

    Initialize(); 

    isRunning = true; 

    while (isRunning) 
    { 
     if (window.Focused) 
     { 
      Update(); 
      LateUpdate(); 
      Render(); 
      Thread.Sleep(16); // hard cap 
     } 
    } 
} 

le problème avec cela, cependant, est que jusqu'à sommeil, le reste de ce code pourrait prendre plus de 16 millisecondes; Pour cela, vous pouvez faire quelques mesures de performance et faire quelque chose comme 10ms à la place.

Une autre façon, en gardant une minuterie active serait quelque chose comme ce qui suit:

public void Run() 
{ 
    window.Show(); 
    window.Focus(); 

    Initialize(); 

    isRunning = true; 

    long limit = 1000/60; 

    while (isRunning) 
    { 
     if (window.Focused) 
     { 
      timer.Restart(); 
      Update(); 
      LateUpdate(); 
      Render(); 
      while (timer.ElapsedMilliseconds < limit) { 
       Thread.Sleep(0); 
      } 
     } 
    } 
} 

On évite ainsi le bouchon « dur » tout en prenant en considération le fait que tout le code jusqu'au sommeil pourrait durer plus longtemps que 16ms, n'entrent donc pas dans la boucle "wait" si le temps requis est passé.

En outre, quelques notes à prendre en compte avec votre code affiché:

d'abord, si vous n'utilisez pas des éléments Windows Form (comme un PictureBox, Button, TextBox, etc.), et au lieu dessinez tous les éléments vous-même (par exemple appeler quelque chose comme Graphics.DrawLine, etc.), vous n'avez pas besoin d'appeler Application.DoEvents; Ce faisant, le thread appelant attend que tous les autres messages Windows Forms aient été traités, ralentissant ainsi la boucle de rendu. Si vous avez effectivement besoin d'appeler Application.DoEvents, il serait préférable de le faire après votre Render(), de manière à inclure cette heure d'appel de fonction dans votre limite de cadre.

Enfin, lorsque vous spécifiez un Thread.Sleep de rien de moins que approximately 20 milliseconds sur un système Windows en temps non réel, les chances sont que le Sleep dormiront réellement plus longtemps en raison de la tranche de temps consacré à un fil sur un système Windows. Ainsi, le Thread.Sleep(1)pourrait dormir pendant 1 milliseconde, ou il pourrait dormir pendant 6 millisecondes; et si la limite de temps est déjà à 14 millisecondes, un sommeil de 6 millisecondes augmenterait votre temps total de 20 millisecondes, ralentissant ainsi votre taux de trame.

La spécification d'une veille de 0 millisecondes annule le reste de la tranche de temps pour le thread appelant à un autre thread de priorité égale prêt à être exécuté; Si aucun autre thread n'est prêt, le thread appelant continue (donc 0-1 millisecondes d'attente, vs 6+). Vous pouvez également utiliser Thread.Yield mais cela agit très différemment de Sleep au niveau du noyau.

Espérons que cela peut aider.